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/Package.h"
18 #include "support/unicode.h"
20 #include "support/lassert.h"
28 // Instanciate static member.
29 string Messages::main_lang_;
33 void cleanTranslation(docstring & trans)
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.
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);
64 # include <libintl.h> // use the header already in the system *EK*
66 # include "../../intl/libintl.h"
69 using namespace lyx::support;
73 void Messages::setDefaultLanguage()
75 char const * env_lang[5] = {"LANGUAGE", "LC_ALL", "LC_MESSAGES",
76 "LC_MESSAGE", "LANG"};
77 for (size_t i = 0; i != 5; ++i) {
78 string const lang = getEnv(env_lang[i]);
81 Messages::main_lang_ = lang;
85 LYXERR(Debug::LOCALE, "Default language not found!");
89 // This version use the traditional gettext.
90 Messages::Messages(string const & l)
91 : lang_(l), warned_(false)
93 // strip off any encoding suffix, i.e., assume 8-bit po files
94 size_t i = lang_.find(".");
95 lang_ = lang_.substr(0, i);
96 LYXERR(Debug::LOCALE, "language(" << lang_ << ")");
100 void Messages::init()
103 string const locale_dir = package().locale_dir().toFilesystemEncoding();
104 char const * c = bindtextdomain(PACKAGE, locale_dir.c_str());
107 LYXERR(Debug::LOCALE, "Error code: " << errno << '\n'
108 << "Directory : " << package().locale_dir().absFilename() << '\n'
109 << "Rtn value : " << c);
112 if (!bind_textdomain_codeset(PACKAGE, ucs4_codeset)) {
113 LYXERR(Debug::LOCALE, "Error code: " << errno << '\n'
114 << "Codeset : " << ucs4_codeset);
119 // Reset default language;
120 setDefaultLanguage();
124 docstring const Messages::get(string const & m) const
129 // Look for the translated string in the cache.
130 TranslationCache::iterator it = cache_.find(m);
131 if (it != cache_.end())
134 // The string was not found, use gettext to generate it
135 static string oldLC_ALL;
136 if (!lang_.empty()) {
137 oldLC_ALL = getEnv("LC_ALL");
138 // This GNU extension overrides any language locale
140 LYXERR(Debug::LOCALE, "Setting LANGUAGE to " << lang_);
141 if (!setEnv("LANGUAGE", lang_))
142 LYXERR(Debug::LOCALE, "\t... failed!");
143 // However, setting LANGUAGE does nothing when the
144 // locale is "C". Therefore we set the locale to
145 // something that is believed to exist on most
146 // systems. The idea is that one should be able to
147 // load German documents even without having de_DE
149 LYXERR(Debug::LOCALE, "Setting LC_ALL to en_US");
150 if (!setEnv("LC_ALL", "en_US"))
151 LYXERR(Debug::LOCALE, "\t... failed!");
152 #ifdef HAVE_LC_MESSAGES
153 setlocale(LC_MESSAGES, "");
157 char const * m_c = m.c_str();
158 char const * trans_c = gettext(m_c);
161 LYXERR(Debug::LOCALE, "Undefined result from gettext");
162 else if (trans_c == m_c) {
163 //LYXERR(Debug::LOCALE, "Same as entered returned");
164 trans = from_ascii(m);
166 //LYXERR(Debug::LOCALE, "We got a translation");
167 // m is actually not a char const * but ucs4 data
168 trans = reinterpret_cast<char_type const *>(trans_c);
171 cleanTranslation(trans);
173 // Reset environment variables as they were.
174 if (!lang_.empty()) {
175 // Reset everything as it was.
176 LYXERR(Debug::LOCALE, "restoring LANGUAGE from " << getEnv("LANGUAGE")
177 << " to " << main_lang_);
178 if (!setEnv("LANGUAGE", main_lang_))
179 LYXERR(Debug::LOCALE, "\t... failed!");
180 LYXERR(Debug::LOCALE, "restoring LC_ALL from " << getEnv("LC_ALL")
181 << " to " << oldLC_ALL);
182 if (!setEnv("LC_ALL", oldLC_ALL))
183 LYXERR(Debug::LOCALE, "\t... failed!");
184 #ifdef HAVE_LC_MESSAGES
185 setlocale(LC_MESSAGES, "");
189 pair<TranslationCache::iterator, bool> result =
190 cache_.insert(make_pair(m, trans));
192 LASSERT(result.second, /**/);
194 return result.first->second;
200 // This is the dummy variant.
204 Messages::Messages(string const & l) {}
206 void Messages::init()
211 docstring const Messages::get(string const & m) const
213 docstring trans = from_ascii(m);
214 cleanTranslation(trans);
228 // This version of the Pimpl utilizes the message capability of
229 // libstdc++ that is distributed with GNU G++.
230 class Messages::Pimpl {
232 typedef messages<char>::catalog catalog;
234 Pimpl(string const & l)
236 loc_gl(lang_.c_str()),
237 mssg_gl(use_facet<messages<char> >(loc_gl))
239 //LYXERR("Messages: language(" << l << ") in dir(" << dir << ")");
241 string const locale_dir = package().locale_dir().toFilesystemEncoding();
242 cat_gl = mssg_gl.open(PACKAGE, loc_gl, locale_dir.c_str());
248 mssg_gl.close(cat_gl);
251 docstring const get(string const & msg) const
253 return mssg_gl.get(cat_gl, 0, 0, msg);
261 messages<char> const & mssg_gl;