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