]> git.lyx.org Git - lyx.git/blob - src/support/Messages.cpp
b9a5bb5545cbb1436ef983eb882ce2bd7683fac4
[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::DEBUG, "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::DEBUG, "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::DEBUG, "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         static string const oldLANGUAGE = getEnv("LANGUAGE");
115         static string const oldLC_ALL = getEnv("LC_ALL");
116         if (!lang_.empty()) {
117                 // This GNU extension overrides any language locale
118                 // wrt gettext.
119                 bool success = setEnv("LANGUAGE", lang_);
120                 if (!success)
121                         LYXERR0("WARNING: Cannot set env LANGUAGE variable to " << lang_);
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                 success = setEnv("LC_ALL", "en_US");
129                 if (!success)
130                         LYXERR0("WARNING: Cannot set env LC_ALL variable to en_US");
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                 LYXERR0("Undefined result from gettext");
141         else if (trans_c == m_c) {
142                 LYXERR(Debug::DEBUG, "Same as entered returned");
143                 trans = from_ascii(m);
144         } else {
145                 LYXERR(Debug::DEBUG, "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                 setEnv("LANGUAGE", oldLANGUAGE);
156                 setEnv("LC_ALL", oldLC_ALL);
157 #ifdef HAVE_LC_MESSAGES
158                 setlocale(LC_MESSAGES, "");
159 #endif
160         }
161
162         pair<TranslationCache::iterator, bool> result =
163                 cache_.insert(make_pair(m, trans));
164
165         LASSERT(result.second, /**/);
166
167         return result.first->second;
168 }
169
170 } // namespace lyx
171
172 #else // ENABLE_NLS
173 // This is the dummy variant.
174
175 namespace lyx {
176
177 Messages::Messages(string const & l) {}
178
179 void Messages::init()
180 {
181 }
182
183
184 docstring const Messages::get(string const & m) const
185 {
186         docstring trans = from_ascii(m);
187         cleanTranslation(trans);
188         return trans;
189 }
190
191 } // namespace lyx
192
193 #endif
194
195 #if 0
196
197 -#include <locale>
198
199 namespace lyx {
200
201 // This version of the Pimpl utilizes the message capability of
202 // libstdc++ that is distributed with GNU G++.
203 class Messages::Pimpl {
204 public:
205         typedef messages<char>::catalog catalog;
206
207         Pimpl(string const & l)
208                 : lang_(l),
209                   loc_gl(lang_.c_str()),
210                   mssg_gl(use_facet<messages<char> >(loc_gl))
211         {
212                 //LYXERR("Messages: language(" << l << ") in dir(" << dir << ")");
213
214                 string const locale_dir = package().locale_dir().toFilesystemEncoding();
215                 cat_gl = mssg_gl.open(PACKAGE, loc_gl, locale_dir.c_str());
216
217         }
218
219         ~Pimpl()
220         {
221                 mssg_gl.close(cat_gl);
222         }
223
224         docstring const get(string const & msg) const
225         {
226                 return mssg_gl.get(cat_gl, 0, 0, msg);
227         }
228 private:
229         ///
230         string lang_;
231         ///
232         locale loc_gl;
233         ///
234         messages<char> const & mssg_gl;
235         ///
236         catalog cat_gl;
237 };
238
239 } // namespace lyx
240
241 #endif