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_;
32 void cleanTranslation(docstring & trans)
35 Some english words have different translations, depending on
36 context. In these cases the original string is augmented by
37 context information (e.g. "To:[[as in 'From page x to page
38 y']]" and "To:[[as in 'From format x to format y']]". This
39 means that we need to filter out everything in double square
40 brackets at the end of the string, otherwise the user sees
41 bogus messages. If we are unable to honour the request we
42 just return what we got in.
44 size_t const pos1 = trans.find(from_ascii("[["));
45 if (pos1 != docstring::npos) {
46 size_t const pos2 = trans.find(from_ascii("]]"), pos1);
47 if (pos2 != docstring::npos)
48 trans.erase(pos1, pos2 - pos1 + 2);
62 # include <libintl.h> // use the header already in the system *EK*
64 # include "intl/libintl.h"
67 using namespace lyx::support;
71 void Messages::setDefaultLanguage()
73 char const * env_lang[5] = {"LANGUAGE", "LC_ALL", "LC_MESSAGES",
74 "LC_MESSAGE", "LANG"};
75 for (size_t i = 0; i != 5; ++i) {
76 string const lang = getEnv(env_lang[i]);
79 Messages::main_lang_ = lang;
83 LYXERR(Debug::LOCALE, "Default language not found!");
87 // This version use the traditional gettext.
88 Messages::Messages(string const & l)
89 : lang_(l), warned_(false)
91 // strip off any encoding suffix, i.e., assume 8-bit po files
92 size_t i = lang_.find(".");
93 lang_ = lang_.substr(0, i);
94 LYXERR(Debug::LOCALE, "language(" << lang_ << ")");
101 string const locale_dir = package().locale_dir().toFilesystemEncoding();
102 char const * c = bindtextdomain(PACKAGE, locale_dir.c_str());
105 LYXERR(Debug::LOCALE, "Error code: " << errno << '\n'
106 << "Directory : " << package().locale_dir().absFileName() << '\n'
107 << "Rtn value : " << c);
110 if (!bind_textdomain_codeset(PACKAGE, ucs4_codeset)) {
111 LYXERR(Debug::LOCALE, "Error code: " << errno << '\n'
112 << "Codeset : " << ucs4_codeset);
117 // Reset default language;
118 setDefaultLanguage();
122 bool Messages::available() const
124 string const test = languageTestString();
125 string const trans = to_utf8(get(test));
126 return !trans.empty() && trans != test;
130 docstring const Messages::get(string const & m) const
135 // Look for the translated string in the cache.
136 TranslationCache::iterator it = cache_.find(m);
137 if (it != cache_.end())
140 // The string was not found, use gettext to generate it
141 static string oldLC_ALL;
142 static string oldLANGUAGE;
143 if (!lang_.empty()) {
144 oldLC_ALL = getEnv("LC_ALL");
145 // This GNU extension overrides any language locale
147 LYXERR(Debug::LOCALE, "Setting LANGUAGE to " << lang_);
148 oldLANGUAGE = getEnv("LANGUAGE");
149 if (!setEnv("LANGUAGE", lang_))
150 LYXERR(Debug::LOCALE, "\t... failed!");
151 // However, setting LANGUAGE does nothing when the
152 // locale is "C". Therefore we set the locale to
153 // something that is believed to exist on most
154 // systems. The idea is that one should be able to
155 // load German documents even without having de_DE
157 LYXERR(Debug::LOCALE, "Setting LC_ALL to en_US");
158 if (!setEnv("LC_ALL", "en_US"))
159 LYXERR(Debug::LOCALE, "\t... failed!");
160 #ifdef HAVE_LC_MESSAGES
161 setlocale(LC_MESSAGES, "");
165 // FIXME: gettext sometimes "forgets" the ucs4_codeset we set
166 // in init(), which leads to severe message corruption (#7371)
167 // We set it again here unconditionally. A real fix must be found!
168 LASSERT(bind_textdomain_codeset(PACKAGE, ucs4_codeset), /**/);
170 char const * m_c = m.c_str();
171 char const * trans_c = gettext(m_c);
174 LYXERR(Debug::LOCALE, "Undefined result from gettext for `" << m << "'.");
175 trans = from_ascii(m);
176 } else if (trans_c == m_c) {
177 //LYXERR(Debug::LOCALE, "Same as entered returned");
178 trans = from_ascii(m);
180 //LYXERR(Debug::LOCALE, "We got a translation");
181 // m is actually not a char const * but ucs4 data
182 trans = reinterpret_cast<char_type const *>(trans_c);
185 cleanTranslation(trans);
187 // Reset environment variables as they were.
188 if (!lang_.empty()) {
189 // Reset everything as it was.
190 LYXERR(Debug::LOCALE, "restoring LANGUAGE from "
191 << getEnv("LANGUAGE")
192 << " to " << oldLANGUAGE);
193 if (!setEnv("LANGUAGE", oldLANGUAGE))
194 LYXERR(Debug::LOCALE, "\t... failed!");
195 LYXERR(Debug::LOCALE, "restoring LC_ALL from " << getEnv("LC_ALL")
196 << " to " << oldLC_ALL);
197 if (!setEnv("LC_ALL", oldLC_ALL))
198 LYXERR(Debug::LOCALE, "\t... failed!");
199 #ifdef HAVE_LC_MESSAGES
200 setlocale(LC_MESSAGES, "");
204 pair<TranslationCache::iterator, bool> result =
205 cache_.insert(make_pair(m, trans));
207 LASSERT(result.second, /**/);
209 return result.first->second;
215 // This is the dummy variant.
219 Messages::Messages(string const & /* l */) {}
221 void Messages::init()
226 docstring const Messages::get(string const & m) const
228 docstring trans = from_ascii(m);
229 cleanTranslation(trans);
234 bool Messages::available() const
249 // This version of the Pimpl utilizes the message capability of
250 // libstdc++ that is distributed with GNU G++.
251 class Messages::Pimpl {
253 typedef messages<char>::catalog catalog;
255 Pimpl(string const & l)
257 loc_gl(lang_.c_str()),
258 mssg_gl(use_facet<messages<char> >(loc_gl))
260 //LYXERR("Messages: language(" << l << ") in dir(" << dir << ")");
262 string const locale_dir = package().locale_dir().toFilesystemEncoding();
263 cat_gl = mssg_gl.open(PACKAGE, loc_gl, locale_dir.c_str());
269 mssg_gl.close(cat_gl);
272 docstring const get(string const & msg) const
274 return mssg_gl.get(cat_gl, 0, 0, msg);
282 messages<char> const & mssg_gl;