]> git.lyx.org Git - lyx.git/blob - src/support/Messages.cpp
update argument labels for Springer classes
[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/lstrings.h"
18 #include "support/Package.h"
19 #include "support/unicode.h"
20
21 #include "support/lassert.h"
22
23 #include <cerrno>
24
25 #  define N_(str) (str)              // for marking strings to be translated
26
27 using namespace std;
28
29 namespace lyx {
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 } // lyx
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 string Messages::language() const
103 {
104         // get the language from the gmo file
105         string const test = N_("[[Replace with the code of your language]]");
106         string const trans = to_utf8(get(test));
107         if (trans == test) {
108                 LYXERR0("Something is weird.");
109                 return string();
110         } else
111                 return trans;
112 }
113
114
115 bool Messages::available(string const & c)
116 {
117         static string locale_dir = package().locale_dir().toFilesystemEncoding();
118         string code = c;
119         // this loops at most twice
120         while (true) {
121                 string const filen = locale_dir + "/" + code 
122                         + "/LC_MESSAGES/" PACKAGE ".mo";
123                 if (FileName(filen).isReadableFile())
124                         return true;
125                 if (contains(code, '_'))
126                         code = token(code, '_', 0);
127                 else return false;
128         }
129         return false;
130
131 }
132
133
134 docstring const Messages::get(string const & m) const
135 {
136         if (m.empty())
137                 return docstring();
138
139         // Look for the translated string in the cache.
140         TranslationCache::iterator it = cache_.find(m);
141         if (it != cache_.end())
142                 return it->second;
143
144         // The string was not found, use gettext to generate it
145         static string oldLC_ALL;
146         static string oldLANGUAGE;
147         if (!lang_.empty()) {
148                 oldLC_ALL = getEnv("LC_ALL");
149                 // This GNU extension overrides any language locale
150                 // wrt gettext.
151                 LYXERR(Debug::LOCALE, "Setting LANGUAGE to " << lang_);
152                 oldLANGUAGE = getEnv("LANGUAGE");
153                 if (!setEnv("LANGUAGE", lang_))
154                         LYXERR(Debug::LOCALE, "\t... failed!");
155                 // However, setting LANGUAGE does nothing when the
156                 // locale is "C". Therefore we set the locale to
157                 // something that is believed to exist on most
158                 // systems. The idea is that one should be able to
159                 // load German documents even without having de_DE
160                 // installed.
161                 LYXERR(Debug::LOCALE, "Setting LC_ALL to en_US");
162                 if (!setEnv("LC_ALL", "en_US"))
163                         LYXERR(Debug::LOCALE, "\t... failed!");
164 #ifdef HAVE_LC_MESSAGES
165                 setlocale(LC_MESSAGES, "");
166 #endif
167         }
168
169         // FIXME: gettext sometimes "forgets" the ucs4_codeset we set
170         // in init(), which leads to severe message corruption (#7371)
171         // We set it again here unconditionally. A real fix must be found!
172         LASSERT(bind_textdomain_codeset(PACKAGE, ucs4_codeset), /**/);
173
174         char const * m_c = m.c_str();
175         char const * trans_c = gettext(m_c);
176         docstring trans;
177         if (!trans_c) {
178                 LYXERR(Debug::LOCALE, "Undefined result from gettext for `" << m << "'.");
179                 trans = from_ascii(m);
180         } else if (trans_c == m_c) {
181                 //LYXERR(Debug::LOCALE, "Same as entered returned");
182                 trans = from_ascii(m);
183         } else {
184                 //LYXERR(Debug::LOCALE, "We got a translation");
185                 // m is actually not a char const * but ucs4 data
186                 trans = reinterpret_cast<char_type const *>(trans_c);
187         }
188
189         cleanTranslation(trans);
190
191         // Reset environment variables as they were.
192         if (!lang_.empty()) {
193                 // Reset everything as it was.
194                 LYXERR(Debug::LOCALE, "restoring LANGUAGE from " 
195                        << getEnv("LANGUAGE")
196                        << " to " << oldLANGUAGE);
197                 if (!setEnv("LANGUAGE", oldLANGUAGE))
198                         LYXERR(Debug::LOCALE, "\t... failed!");
199                 LYXERR(Debug::LOCALE, "restoring LC_ALL from " << getEnv("LC_ALL")
200                         << " to " << oldLC_ALL);
201                 if (!setEnv("LC_ALL", oldLC_ALL))
202                         LYXERR(Debug::LOCALE, "\t... failed!");
203 #ifdef HAVE_LC_MESSAGES
204                 setlocale(LC_MESSAGES, "");
205 #endif
206         }
207
208         pair<TranslationCache::iterator, bool> result =
209                 cache_.insert(make_pair(m, trans));
210
211         LASSERT(result.second, /**/);
212
213         return result.first->second;
214 }
215
216 } // namespace lyx
217
218 #else // ENABLE_NLS
219 // This is the dummy variant.
220
221 namespace lyx {
222
223 Messages::Messages(string const & /* l */) {}
224
225 void Messages::init()
226 {
227 }
228
229
230 docstring const Messages::get(string const & m) const
231 {
232         docstring trans = from_ascii(m);
233         cleanTranslation(trans);
234         return trans;
235 }
236
237 std::string Messages::language() const
238     {
239         return string();
240     }
241
242 bool Messages::available(string const & /* c */)
243 {
244         return false;
245 }
246
247 } // namespace lyx
248
249 #endif
250
251 #if 0
252
253 -#include <locale>
254
255 namespace lyx {
256
257 // This version of the Pimpl utilizes the message capability of
258 // libstdc++ that is distributed with GNU G++.
259 class Messages::Pimpl {
260 public:
261         typedef messages<char>::catalog catalog;
262
263         Pimpl(string const & l)
264                 : lang_(l),
265                   loc_gl(lang_.c_str()),
266                   mssg_gl(use_facet<messages<char> >(loc_gl))
267         {
268                 //LYXERR("Messages: language(" << l << ") in dir(" << dir << ")");
269
270                 string const locale_dir = package().locale_dir().toFilesystemEncoding();
271                 cat_gl = mssg_gl.open(PACKAGE, loc_gl, locale_dir.c_str());
272
273         }
274
275         ~Pimpl()
276         {
277                 mssg_gl.close(cat_gl);
278         }
279
280         docstring const get(string const & msg) const
281         {
282                 return mssg_gl.get(cat_gl, 0, 0, msg);
283         }
284 private:
285         ///
286         string lang_;
287         ///
288         locale loc_gl;
289         ///
290         messages<char> const & mssg_gl;
291         ///
292         catalog cat_gl;
293 };
294
295 } // namespace lyx
296
297 #endif