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