]> git.lyx.org Git - lyx.git/blob - src/support/Messages.cpp
Move debug.{cpp,h}, Messages.{cpp,h} and gettext.{cpp,h} to support/.
[lyx.git] / src / support / Messages.cpp
1 /* \file Messages.cpp
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 "support/Messages.h"
13
14 #include "support/debug.h"
15 #include "support/docstring.h"
16 #include "support/environment.h"
17 #include "support/Package.h"
18 #include "support/unicode.h"
19
20 #include <boost/current_function.hpp>
21
22 #include <cerrno>
23
24 using std::map;
25 using std::string;
26
27 namespace {
28
29 using lyx::docstring;
30 using lyx::from_ascii;
31
32 void cleanTranslation(docstring & trans) 
33 {
34         /*
35           Some english words have different translations, depending on
36           context. In these cases the original string is augmented by
37           context information (e.g. "To:[[as in 'From page x to page
38           y']]" and "To:[[as in 'From format x to format y']]". This
39           means that we need to filter out everything in double square
40           brackets at the end of the string, otherwise the user sees
41           bogus messages. If we are unable to honour the request we
42           just return what we got in.
43         */
44         size_t const pos1 = trans.find(from_ascii("[["));
45         if (pos1 != docstring::npos) {
46                 size_t const pos2 = trans.find(from_ascii("]]"), pos1);
47                 if (pos2 != docstring::npos) 
48                         trans.erase(pos1, pos2 - pos1 + 2);
49         }
50 }
51
52 }
53
54
55 #ifdef ENABLE_NLS
56
57 #  ifdef HAVE_LOCALE_H
58 #    include <locale.h>
59 #  endif
60
61 #  if HAVE_GETTEXT
62 #    include <libintl.h>      // use the header already in the system *EK*
63 #  else
64 #    include "../../intl/libintl.h"
65 #  endif
66
67 namespace lyx {
68
69 using support::package;
70 using support::getEnv;
71 using support::setEnv;
72
73
74 // This version use the traditional gettext.
75 Messages::Messages(string const & l)
76         : lang_(l), warned_(false)
77 {
78         // strip off any encoding suffix, i.e., assume 8-bit po files
79         string::size_type i = lang_.find(".");
80         lang_ = lang_.substr(0, i);
81         LYXERR(Debug::DEBUG, BOOST_CURRENT_FUNCTION
82                 << ": language(" << lang_ << ")");
83 }
84
85
86 void Messages::init()
87 {
88         errno = 0;
89         string const locale_dir = package().locale_dir().toFilesystemEncoding();
90         char const * c = bindtextdomain(PACKAGE, locale_dir.c_str());
91         int e = errno;
92         if (e) {
93                 LYXERR(Debug::DEBUG, BOOST_CURRENT_FUNCTION << '\n'
94                         << "Error code: " << errno << '\n'
95                         << "Directory : " << package().locale_dir().absFilename() << '\n'
96                         << "Rtn value : " << c);
97         }
98
99         if (!bind_textdomain_codeset(PACKAGE, ucs4_codeset)) {
100                 LYXERR(Debug::DEBUG, BOOST_CURRENT_FUNCTION << '\n'
101                         << "Error code: " << errno << '\n'
102                         << "Codeset   : " << ucs4_codeset << '\n');
103         }
104
105         textdomain(PACKAGE);
106 }
107
108
109 docstring const Messages::get(string const & m) const
110 {
111         if (m.empty())
112                 return docstring();
113
114         // Look for the translated string in the cache.
115         TranslationCache::iterator it = cache_.find(m);
116         if (it != cache_.end())
117                 return it->second;
118
119         // The string was not found, use gettext to generate it
120
121         string const oldLANGUAGE = getEnv("LANGUAGE");
122         string const oldLC_ALL = getEnv("LC_ALL");
123         if (!lang_.empty()) {
124                 // This GNU extension overrides any language locale
125                 // wrt gettext.
126                 setEnv("LANGUAGE", lang_);
127                 // However, setting LANGUAGE does nothing when the
128                 // locale is "C". Therefore we set the locale to
129                 // something that is believed to exist on most
130                 // systems. The idea is that one should be able to
131                 // load German documents even without having de_DE
132                 // installed.
133                 setEnv("LC_ALL", "en_US");
134 #ifdef HAVE_LC_MESSAGES
135                 setlocale(LC_MESSAGES, "");
136 #endif
137         }
138
139         char const * m_c = m.c_str();
140         char const * trans_c = gettext(m_c);
141         docstring trans;
142         if (!trans_c)
143                 LYXERR0("Undefined result from gettext");
144         else if (trans_c == m_c) {
145                 LYXERR(Debug::DEBUG, "Same as entered returned");
146                 trans = from_ascii(m);
147         } else {
148                 LYXERR(Debug::DEBUG, "We got a translation");
149                 // m is actually not a char const * but ucs4 data
150                 trans = reinterpret_cast<char_type const *>(trans_c);
151         }
152
153         cleanTranslation(trans);
154
155         // Reset environment variables as they were.
156         if (!lang_.empty()) {
157                 // Reset everything as it was.
158                 setEnv("LANGUAGE", oldLANGUAGE);
159                 setEnv("LC_ALL", oldLC_ALL);
160 #ifdef HAVE_LC_MESSAGES
161                 setlocale(LC_MESSAGES, "");
162 #endif
163         }
164
165         std::pair<TranslationCache::iterator, bool> result =
166                 cache_.insert(std::make_pair(m, trans));
167
168         BOOST_ASSERT(result.second);
169
170         return result.first->second;
171 }
172
173 } // namespace lyx
174
175 #else // ENABLE_NLS
176 // This is the dummy variant.
177
178 namespace lyx {
179
180 Messages::Messages(string const & l) {}
181
182 void Messages::init()
183 {
184 }
185
186
187 docstring const Messages::get(string const & m) const
188 {
189         docstring trans = from_ascii(m);
190         cleanTranslation(trans);
191         return trans;
192 }
193
194 } // namespace lyx
195
196 #endif
197
198 #if 0
199
200 -#include <locale>
201
202 namespace lyx {
203
204 // This version of the Pimpl utilizes the message capability of
205 // libstdc++ that is distributed with GNU G++.
206 class Messages::Pimpl {
207 public:
208         typedef std::messages<char>::catalog catalog;
209
210         Pimpl(string const & l)
211                 : lang_(l),
212                   loc_gl(lang_.c_str()),
213                   mssg_gl(std::use_facet<std::messages<char> >(loc_gl))
214         {
215                 //LYXERR("Messages: language(" << l << ") in dir(" << dir << ")");
216
217                 string const locale_dir = package().locale_dir().toFilesystemEncoding();
218                 cat_gl = mssg_gl.open(PACKAGE, loc_gl, locale_dir.c_str());
219
220         }
221
222         ~Pimpl()
223         {
224                 mssg_gl.close(cat_gl);
225         }
226
227         docstring const get(string const & msg) const
228         {
229                 return mssg_gl.get(cat_gl, 0, 0, msg);
230         }
231 private:
232         ///
233         string lang_;
234         ///
235         std::locale loc_gl;
236         ///
237         std::messages<char> const & mssg_gl;
238         ///
239         catalog cat_gl;
240 };
241
242 } // namespace lyx
243
244 #endif