]> git.lyx.org Git - lyx.git/blob - src/support/Messages.cpp
16a286c3d3f152287cbb6e2d91eb6d5efe924553
[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                 setEnv("LANGUAGE", lang_);
120                 // However, setting LANGUAGE does nothing when the
121                 // locale is "C". Therefore we set the locale to
122                 // something that is believed to exist on most
123                 // systems. The idea is that one should be able to
124                 // load German documents even without having de_DE
125                 // installed.
126                 setEnv("LC_ALL", "en_US");
127 #ifdef HAVE_LC_MESSAGES
128                 setlocale(LC_MESSAGES, "");
129 #endif
130         }
131
132         char const * m_c = m.c_str();
133         char const * trans_c = gettext(m_c);
134         docstring trans;
135         if (!trans_c)
136                 LYXERR0("Undefined result from gettext");
137         else if (trans_c == m_c) {
138                 LYXERR(Debug::DEBUG, "Same as entered returned");
139                 trans = from_ascii(m);
140         } else {
141                 LYXERR(Debug::DEBUG, "We got a translation");
142                 // m is actually not a char const * but ucs4 data
143                 trans = reinterpret_cast<char_type const *>(trans_c);
144         }
145
146         cleanTranslation(trans);
147
148         // Reset environment variables as they were.
149         if (!lang_.empty()) {
150                 // Reset everything as it was.
151                 setEnv("LANGUAGE", oldLANGUAGE);
152                 setEnv("LC_ALL", oldLC_ALL);
153 #ifdef HAVE_LC_MESSAGES
154                 setlocale(LC_MESSAGES, "");
155 #endif
156         }
157
158         pair<TranslationCache::iterator, bool> result =
159                 cache_.insert(make_pair(m, trans));
160
161         LASSERT(result.second, /**/);
162
163         return result.first->second;
164 }
165
166 } // namespace lyx
167
168 #else // ENABLE_NLS
169 // This is the dummy variant.
170
171 namespace lyx {
172
173 Messages::Messages(string const & l) {}
174
175 void Messages::init()
176 {
177 }
178
179
180 docstring const Messages::get(string const & m) const
181 {
182         docstring trans = from_ascii(m);
183         cleanTranslation(trans);
184         return trans;
185 }
186
187 } // namespace lyx
188
189 #endif
190
191 #if 0
192
193 -#include <locale>
194
195 namespace lyx {
196
197 // This version of the Pimpl utilizes the message capability of
198 // libstdc++ that is distributed with GNU G++.
199 class Messages::Pimpl {
200 public:
201         typedef messages<char>::catalog catalog;
202
203         Pimpl(string const & l)
204                 : lang_(l),
205                   loc_gl(lang_.c_str()),
206                   mssg_gl(use_facet<messages<char> >(loc_gl))
207         {
208                 //LYXERR("Messages: language(" << l << ") in dir(" << dir << ")");
209
210                 string const locale_dir = package().locale_dir().toFilesystemEncoding();
211                 cat_gl = mssg_gl.open(PACKAGE, loc_gl, locale_dir.c_str());
212
213         }
214
215         ~Pimpl()
216         {
217                 mssg_gl.close(cat_gl);
218         }
219
220         docstring const get(string const & msg) const
221         {
222                 return mssg_gl.get(cat_gl, 0, 0, msg);
223         }
224 private:
225         ///
226         string lang_;
227         ///
228         locale loc_gl;
229         ///
230         messages<char> const & mssg_gl;
231         ///
232         catalog cat_gl;
233 };
234
235 } // namespace lyx
236
237 #endif