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