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 static string oldLANGUAGE;
137 if (!lang_.empty()) {
138 oldLC_ALL = getEnv("LC_ALL");
139 // This GNU extension overrides any language locale
141 LYXERR(Debug::LOCALE, "Setting LANGUAGE to " << lang_);
142 oldLANGUAGE = getEnv("LANGUAGE");
143 if (!setEnv("LANGUAGE", lang_))
144 LYXERR(Debug::LOCALE, "\t... failed!");
145 // However, setting LANGUAGE does nothing when the
146 // locale is "C". Therefore we set the locale to
147 // something that is believed to exist on most
148 // systems. The idea is that one should be able to
149 // load German documents even without having de_DE
151 LYXERR(Debug::LOCALE, "Setting LC_ALL to en_US");
152 if (!setEnv("LC_ALL", "en_US"))
153 LYXERR(Debug::LOCALE, "\t... failed!");
154 #ifdef HAVE_LC_MESSAGES
155 setlocale(LC_MESSAGES, "");
159 char const * m_c = m.c_str();
160 char const * trans_c = gettext(m_c);
163 LYXERR(Debug::LOCALE, "Undefined result from gettext");
164 else if (trans_c == m_c) {
165 //LYXERR(Debug::LOCALE, "Same as entered returned");
166 trans = from_ascii(m);
168 //LYXERR(Debug::LOCALE, "We got a translation");
169 // m is actually not a char const * but ucs4 data
170 trans = reinterpret_cast<char_type const *>(trans_c);
173 cleanTranslation(trans);
175 // Reset environment variables as they were.
176 if (!lang_.empty()) {
177 // Reset everything as it was.
178 LYXERR(Debug::LOCALE, "restoring LANGUAGE from "
179 << getEnv("LANGUAGE")
180 << " to " << oldLANGUAGE);
181 if (!setEnv("LANGUAGE", oldLANGUAGE))
182 LYXERR(Debug::LOCALE, "\t... failed!");
183 LYXERR(Debug::LOCALE, "restoring LC_ALL from " << getEnv("LC_ALL")
184 << " to " << oldLC_ALL);
185 if (!setEnv("LC_ALL", oldLC_ALL))
186 LYXERR(Debug::LOCALE, "\t... failed!");
187 #ifdef HAVE_LC_MESSAGES
188 setlocale(LC_MESSAGES, "");
192 pair<TranslationCache::iterator, bool> result =
193 cache_.insert(make_pair(m, trans));
195 LASSERT(result.second, /**/);
197 return result.first->second;
203 // This is the dummy variant.
207 Messages::Messages(string const & l) {}
209 void Messages::init()
214 docstring const Messages::get(string const & m) const
216 docstring trans = from_ascii(m);
217 cleanTranslation(trans);
231 // This version of the Pimpl utilizes the message capability of
232 // libstdc++ that is distributed with GNU G++.
233 class Messages::Pimpl {
235 typedef messages<char>::catalog catalog;
237 Pimpl(string const & l)
239 loc_gl(lang_.c_str()),
240 mssg_gl(use_facet<messages<char> >(loc_gl))
242 //LYXERR("Messages: language(" << l << ") in dir(" << dir << ")");
244 string const locale_dir = package().locale_dir().toFilesystemEncoding();
245 cat_gl = mssg_gl.open(PACKAGE, loc_gl, locale_dir.c_str());
251 mssg_gl.close(cat_gl);
254 docstring const get(string const & msg) const
256 return mssg_gl.get(cat_gl, 0, 0, msg);
264 messages<char> const & mssg_gl;