]> git.lyx.org Git - lyx.git/blob - src/messages.C
- rename CacheType
[lyx.git] / src / messages.C
1 /* \file messages.C
2  * This file is part of LyX, the document processor.
3  * Licence details can be found in the file COPYING.
4  *
5  * \author Lars Gullik Bjønnes
6  *
7  * Full author contact details are available in file CREDITS.
8  */
9
10 #include <config.h>
11
12 #include "debug.h"
13 #include "messages.h"
14 #include "support/filetools.h"
15 #include "support/environment.h"
16 #include "support/package.h"
17 #include "support/docstring.h"
18 #include "support/types.h"
19
20 #include <boost/current_function.hpp>
21 #include <boost/regex.hpp>
22
23 #include <cerrno>
24 #include <map>
25
26 using std::endl;
27 using std::string;
28
29 namespace lyx {
30
31 using support::package;
32 using support::getEnv;
33 using support::setEnv;
34
35
36 static boost::regex const reg("^([^\\[]*)\\[\\[[^\\]]*\\]\\]$");
37
38
39 #ifdef ENABLE_NLS
40
41
42 #if 0
43
44 -#include <locale>
45
46 // This version of the Pimpl utilizes the message capability of
47 // libstdc++ that is distributed with GNU G++.
48 class Messages::Pimpl {
49 public:
50         typedef std::messages<char>::catalog catalog;
51
52         Pimpl(string const & l)
53                 : lang_(l),
54                   loc_gl(lang_.c_str()),
55                   mssg_gl(std::use_facet<std::messages<char> >(loc_gl))
56         {
57                 //lyxerr << "Messages: language(" << l
58                 //       << ") in dir(" << dir << ")" << endl;
59
60                 cat_gl = mssg_gl.open(PACKAGE, loc_gl, package().locale_dir().c_str());
61
62         }
63
64         ~Pimpl()
65         {
66                 mssg_gl.close(cat_gl);
67         }
68
69         docstring const get(string const & msg) const
70         {
71                 return mssg_gl.get(cat_gl, 0, 0, msg);
72         }
73 private:
74         ///
75         string lang_;
76         ///
77         std::locale loc_gl;
78         ///
79         std::messages<char> const & mssg_gl;
80         ///
81         catalog cat_gl;
82 };
83 #else
84
85 #ifdef HAVE_LOCALE_H
86 #  include <locale.h>
87 #endif
88
89 #  if HAVE_GETTEXT
90 #    include <libintl.h>      // use the header already in the system *EK*
91 #  else
92 #    include "../intl/libintl.h"
93 #  endif
94
95 // This is a more traditional variant.
96 class Messages::Pimpl {
97 public:
98         Pimpl(string const & l)
99                 : lang_(l)
100         {
101                 if ( lang_.empty() ) {
102                         char const * lc_msgs = 0;
103 #ifdef HAVE_LC_MESSAGES
104                         lc_msgs = setlocale(LC_MESSAGES, NULL);
105 #endif
106                         lang_ = lc_msgs ? lc_msgs : "";
107                 }
108                 // strip off any encoding suffix, i.e., assume 8-bit po files
109                 string::size_type i = lang_.find(".");
110                 lang_ = lang_.substr(0, i);
111                 lyxerr[Debug::DEBUG] << BOOST_CURRENT_FUNCTION
112                                      << ": language(" << lang_ << ")" << endl;
113         }
114
115         ~Pimpl() {}
116
117         docstring const & get(string const & m) const
118         {
119                 if (m.empty()) {
120                         dummy_string_.clear();
121                         return dummy_string_;
122                 }
123
124                 // Look for the translated string in the cache.
125                 TranslationCache::iterator it = cache_.find(m);
126                 if (it != cache_.end())
127                         return it->second;
128                 // The string was not found, use gettext to generate it:
129
130                 // In this order, see support/filetools.C:
131                 string lang = getEnv("LC_ALL");
132                 if (lang.empty()) {
133                         lang = getEnv("LC_MESSAGES");
134                         if (lang.empty()) {
135                                 lang = getEnv("LANG");
136                                 if (lang.empty())
137                                         lang = "C";
138                         }
139                 }
140 #ifdef HAVE_LC_MESSAGES
141                 char const * lc_msgs = setlocale(LC_MESSAGES, lang_.c_str());
142 #endif
143                 // setlocale fails (returns NULL) if the corresponding locale
144                 // is not installed.
145                 // On windows (mingw and cygwin) it always returns NULL.
146                 // Since this method gets called for every translatable
147                 // buffer string like e.g. "Figure:" we warn only once.
148 #if !defined(_WIN32) && !defined(__CYGWIN__)
149                 static bool warned = false;
150                 if (!warned && !lc_msgs) {
151                         warned = true;
152                         lyxerr << "Locale " << lang_ << " could not be set" << endl;
153                 }
154 #endif
155                 // CTYPE controls what getmessage thinks what encoding the po file uses
156                 char const * lc_ctype = setlocale(LC_CTYPE, NULL);
157                 string oldCTYPE = lc_ctype ? lc_ctype : "";
158
159                 setlocale(LC_CTYPE, lang_.c_str());
160                 errno = 0;
161                 char const * c = bindtextdomain(PACKAGE, package().locale_dir().c_str());
162                 int e = errno;
163                 if (e) {
164                         lyxerr[Debug::DEBUG]
165                                 << BOOST_CURRENT_FUNCTION << '\n'
166                                 << "Error code: " << errno << '\n'
167                                 << "Lang, mess: " << lang_ << " " << m << '\n'
168                                 << "Directory : " << package().locale_dir() << '\n'
169                                 << "Rtn value : " << c << endl;
170                 }
171 #ifdef WORDS_BIGENDIAN
172                 static const char * codeset = "UCS-4BE";
173 #else
174                 static const char * codeset = "UCS-4LE";
175 #endif
176                 if (!bind_textdomain_codeset(PACKAGE, codeset)) {
177                         lyxerr[Debug::DEBUG]
178                                 << BOOST_CURRENT_FUNCTION << '\n'
179                                 << "Error code: " << errno << '\n'
180                                 << "Codeset   : " << codeset << '\n'
181                                 << endl;
182                 }
183
184                 textdomain(PACKAGE);
185                 char const * tmp = m.c_str();
186                 char const * msg = gettext(tmp);
187                 docstring translated;
188                 if (!msg || msg == tmp) {
189                         if (!msg)
190                                 lyxerr << "Undefined result from gettext" << endl;
191                         //else
192                         //      lyxerr << "Same as entered returned" << endl;
193                         // Some english words have different translations,
194                         // depending on context. In these cases the original
195                         // string is augmented by context information (e.g.
196                         // "To:[[as in 'From page x to page y']]" and
197                         // "To:[[as in 'From format x to format y']]".
198                         // This means that we need to filter out everything
199                         // in double square brackets at the end of the
200                         // string, otherwise the user sees bogus messages.
201                         // If we are unable to honour the request we just
202                         // return what we got in.
203                         boost::smatch sub;
204                         if (regex_match(m, sub, reg))
205                                 translated = from_ascii(sub.str(1));
206                         else
207                                 translated = from_ascii(tmp);
208                 } else {
209                         lyxerr[Debug::DEBUG] << "We got a translation" << endl;
210                         char_type const * ucs4 = reinterpret_cast<char_type const *>(msg);
211                         translated = ucs4;
212                 }
213 #ifdef HAVE_LC_MESSAGES
214                 setlocale(LC_MESSAGES, lang.c_str());
215 #endif
216                 setlocale(LC_CTYPE, oldCTYPE.c_str());
217
218                 if (!cache_.insert(std::make_pair(m, translated)).second) {
219                         lyxerr << "WARNING: cannot fill-in gettext cache in Messages::get()!" << endl;
220                         dummy_string_ = translated;
221                         return dummy_string_;
222                 }
223
224                 it = cache_.insert(std::make_pair(m, translated)).first;
225                 return it->second;
226         }
227 private:
228         ///
229         string lang_;
230         typedef std::map<string, docstring> TranslationCache;
231         /// Internal cache for gettext translated strings.
232         /// This is needed for performance reason within \c updateLabels()
233         /// under Windows.
234         mutable TranslationCache cache_;
235         /// Dummy string which serves as a storage place if something goes
236         /// wrong with the translation cache.
237         mutable docstring dummy_string_;
238 };
239 #endif
240
241 #else // ENABLE_NLS
242 // This is the dummy variant.
243 class Messages::Pimpl {
244 public:
245         Pimpl(string const &) {}
246
247         ~Pimpl() {}
248
249         docstring const get(string const & m) const
250         {
251                 // See comment above
252                 boost::smatch sub;
253                 if (regex_match(m, sub, reg))
254                         return from_ascii(sub.str(1));
255                 else
256                         return from_ascii(m);
257         }
258 };
259 #endif
260
261
262 Messages::Messages()
263         : pimpl_(new Pimpl(""))
264 {}
265
266
267 Messages::Messages(string const & l)
268         : pimpl_(new Pimpl(l))
269 {}
270
271
272 // We need this for the sake of scoped_ptr
273 Messages::~Messages()
274 {}
275
276
277 docstring const & Messages::get(string const & msg) const
278 {
279         return pimpl_->get(msg);
280 }
281
282
283 } // namespace lyx