2 * This file is part of LyX, the document processor.
3 * Licence details can be found in the file COPYING.
5 * \author Lars Gullik Bjønnes
7 * Full author contact details are available in file CREDITS.
12 #include "support/Messages.h"
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"
21 #include "support/lassert.h"
29 // Instanciate static member.
30 string Messages::main_lang_;
34 void cleanTranslation(docstring & trans)
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.
46 size_t const pos1 = trans.find(from_ascii("[["));
47 if (pos1 != docstring::npos) {
48 size_t const pos2 = trans.find(from_ascii("]]"), pos1);
49 if (pos2 != docstring::npos)
50 trans.erase(pos1, pos2 - pos1 + 2);
65 # include <libintl.h> // use the header already in the system *EK*
67 # include "intl/libintl.h"
70 using namespace lyx::support;
74 void Messages::setDefaultLanguage()
76 char const * env_lang[5] = {"LANGUAGE", "LC_ALL", "LC_MESSAGES",
77 "LC_MESSAGE", "LANG"};
78 for (size_t i = 0; i != 5; ++i) {
79 string const lang = getEnv(env_lang[i]);
82 Messages::main_lang_ = lang;
86 LYXERR(Debug::LOCALE, "Default language not found!");
90 // This version use the traditional gettext.
91 Messages::Messages(string const & l)
92 : lang_(l), warned_(false)
94 // strip off any encoding suffix, i.e., assume 8-bit po files
95 size_t i = lang_.find(".");
96 lang_ = lang_.substr(0, i);
97 LYXERR(Debug::LOCALE, "language(" << lang_ << ")");
101 void Messages::init()
104 string const locale_dir = package().locale_dir().toFilesystemEncoding();
105 char const * c = bindtextdomain(PACKAGE, locale_dir.c_str());
108 LYXERR(Debug::LOCALE, "Error code: " << errno << '\n'
109 << "Directory : " << package().locale_dir().absFileName() << '\n'
110 << "Rtn value : " << c);
113 if (!bind_textdomain_codeset(PACKAGE, ucs4_codeset)) {
114 LYXERR(Debug::LOCALE, "Error code: " << errno << '\n'
115 << "Codeset : " << ucs4_codeset);
120 // Reset default language;
121 setDefaultLanguage();
125 bool Messages::available() const
127 string const test = languageTestString();
128 string const trans = to_utf8(get(test));
129 return !trans.empty() && trans != test;
133 docstring const Messages::get(string const & m) const
138 // Look for the translated string in the cache.
139 TranslationCache::iterator it = cache_.find(m);
140 if (it != cache_.end())
143 // The string was not found, use gettext to generate it
144 static string oldLC_ALL;
145 static string oldLANGUAGE;
146 if (!lang_.empty()) {
147 oldLC_ALL = getEnv("LC_ALL");
148 // This GNU extension overrides any language locale
150 LYXERR(Debug::LOCALE, "Setting LANGUAGE to " << lang_);
151 oldLANGUAGE = getEnv("LANGUAGE");
152 if (!setEnv("LANGUAGE", lang_))
153 LYXERR(Debug::LOCALE, "\t... failed!");
154 // However, setting LANGUAGE does nothing when the
155 // locale is "C". Therefore we set the locale to
156 // something that is believed to exist on most
157 // systems. The idea is that one should be able to
158 // load German documents even without having de_DE
160 LYXERR(Debug::LOCALE, "Setting LC_ALL to en_US");
161 if (!setEnv("LC_ALL", "en_US"))
162 LYXERR(Debug::LOCALE, "\t... failed!");
163 #ifdef HAVE_LC_MESSAGES
164 setlocale(LC_MESSAGES, "");
168 // FIXME: gettext sometimes "forgets" the ucs4_codeset we set
169 // in init(), which leads to severe message corruption (#7371)
170 // We set it again here unconditionally. A real fix must be found!
171 LASSERT(bind_textdomain_codeset(PACKAGE, ucs4_codeset), /**/);
173 char const * m_c = m.c_str();
174 char const * trans_c = gettext(m_c);
177 LYXERR(Debug::LOCALE, "Undefined result from gettext for `" << m << "'.");
178 trans = from_ascii(m);
179 } else if (trans_c == m_c) {
180 //LYXERR(Debug::LOCALE, "Same as entered returned");
181 trans = from_ascii(m);
183 //LYXERR(Debug::LOCALE, "We got a translation");
184 // m is actually not a char const * but ucs4 data
185 trans = reinterpret_cast<char_type const *>(trans_c);
188 cleanTranslation(trans);
190 // Reset environment variables as they were.
191 if (!lang_.empty()) {
192 // Reset everything as it was.
193 LYXERR(Debug::LOCALE, "restoring LANGUAGE from "
194 << getEnv("LANGUAGE")
195 << " to " << oldLANGUAGE);
196 if (!setEnv("LANGUAGE", oldLANGUAGE))
197 LYXERR(Debug::LOCALE, "\t... failed!");
198 LYXERR(Debug::LOCALE, "restoring LC_ALL from " << getEnv("LC_ALL")
199 << " to " << oldLC_ALL);
200 if (!setEnv("LC_ALL", oldLC_ALL))
201 LYXERR(Debug::LOCALE, "\t... failed!");
202 #ifdef HAVE_LC_MESSAGES
203 setlocale(LC_MESSAGES, "");
207 pair<TranslationCache::iterator, bool> result =
208 cache_.insert(make_pair(m, trans));
210 LASSERT(result.second, /**/);
212 return result.first->second;
218 // This is the dummy variant.
222 Messages::Messages(string const & /* l */) {}
224 void Messages::init()
229 docstring const Messages::get(string const & m) const
231 docstring trans = from_ascii(m);
232 cleanTranslation(trans);
237 bool Messages::available() const
252 // This version of the Pimpl utilizes the message capability of
253 // libstdc++ that is distributed with GNU G++.
254 class Messages::Pimpl {
256 typedef messages<char>::catalog catalog;
258 Pimpl(string const & l)
260 loc_gl(lang_.c_str()),
261 mssg_gl(use_facet<messages<char> >(loc_gl))
263 //LYXERR("Messages: language(" << l << ") in dir(" << dir << ")");
265 string const locale_dir = package().locale_dir().toFilesystemEncoding();
266 cat_gl = mssg_gl.open(PACKAGE, loc_gl, locale_dir.c_str());
272 mssg_gl.close(cat_gl);
275 docstring const get(string const & msg) const
277 return mssg_gl.get(cat_gl, 0, 0, msg);
285 messages<char> const & mssg_gl;