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