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"
29 using lyx::from_ascii;
31 void cleanTranslation(docstring & trans)
34 Some english words have different translations, depending on
35 context. In these cases the original string is augmented by
36 context information (e.g. "To:[[as in 'From page x to page
37 y']]" and "To:[[as in 'From format x to format y']]". This
38 means that we need to filter out everything in double square
39 brackets at the end of the string, otherwise the user sees
40 bogus messages. If we are unable to honour the request we
41 just return what we got in.
43 size_t const pos1 = trans.find(from_ascii("[["));
44 if (pos1 != docstring::npos) {
45 size_t const pos2 = trans.find(from_ascii("]]"), pos1);
46 if (pos2 != docstring::npos)
47 trans.erase(pos1, pos2 - pos1 + 2);
61 # include <libintl.h> // use the header already in the system *EK*
63 # include "../../intl/libintl.h"
66 using namespace lyx::support;
70 void Messages::setDefaultLanguage()
72 char * env_lang[5] = {"LANGUAGE", "LC_ALL", "LC_MESSAGES", "LC_MESSAGE",
74 for (size_t i = 0; i != 5; ++i) {
75 string const lang = getEnv(env_lang[i]);
78 Messages::main_lang_ = lang;
82 LYXERR(Debug::LOCALE, "Default language not found!");
86 // Instanciate static member.
87 string Messages::main_lang_;
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 docstring const Messages::get(string const & m) const
130 // Look for the translated string in the cache.
131 TranslationCache::iterator it = cache_.find(m);
132 if (it != cache_.end())
135 // The string was not found, use gettext to generate it
136 static string oldLC_ALL;
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 if (!setEnv("LANGUAGE", lang_))
143 LYXERR(Debug::LOCALE, "\t... failed!");
144 // However, setting LANGUAGE does nothing when the
145 // locale is "C". Therefore we set the locale to
146 // something that is believed to exist on most
147 // systems. The idea is that one should be able to
148 // load German documents even without having de_DE
150 LYXERR(Debug::LOCALE, "Setting LC_ALL to en_US");
151 if (!setEnv("LC_ALL", "en_US"))
152 LYXERR(Debug::LOCALE, "\t... failed!");
153 #ifdef HAVE_LC_MESSAGES
154 setlocale(LC_MESSAGES, "");
158 char const * m_c = m.c_str();
159 char const * trans_c = gettext(m_c);
162 LYXERR(Debug::LOCALE, "Undefined result from gettext");
163 else if (trans_c == m_c) {
164 //LYXERR(Debug::LOCALE, "Same as entered returned");
165 trans = from_ascii(m);
167 //LYXERR(Debug::LOCALE, "We got a translation");
168 // m is actually not a char const * but ucs4 data
169 trans = reinterpret_cast<char_type const *>(trans_c);
172 cleanTranslation(trans);
174 // Reset environment variables as they were.
175 if (!lang_.empty()) {
176 // Reset everything as it was.
177 LYXERR(Debug::LOCALE, "restoring LANGUAGE from " << getEnv("LANGUAGE")
178 << " to " << main_lang_);
179 if (!setEnv("LANGUAGE", main_lang_))
180 LYXERR(Debug::LOCALE, "\t... failed!");
181 LYXERR(Debug::LOCALE, "restoring LC_ALL from " << getEnv("LC_ALL")
182 << " to " << oldLC_ALL);
183 if (!setEnv("LC_ALL", oldLC_ALL))
184 LYXERR(Debug::LOCALE, "\t... failed!");
185 #ifdef HAVE_LC_MESSAGES
186 setlocale(LC_MESSAGES, "");
190 pair<TranslationCache::iterator, bool> result =
191 cache_.insert(make_pair(m, trans));
193 LASSERT(result.second, /**/);
195 return result.first->second;
201 // This is the dummy variant.
205 Messages::Messages(string const & l) {}
207 void Messages::init()
212 docstring const Messages::get(string const & m) const
214 docstring trans = from_ascii(m);
215 cleanTranslation(trans);
229 // This version of the Pimpl utilizes the message capability of
230 // libstdc++ that is distributed with GNU G++.
231 class Messages::Pimpl {
233 typedef messages<char>::catalog catalog;
235 Pimpl(string const & l)
237 loc_gl(lang_.c_str()),
238 mssg_gl(use_facet<messages<char> >(loc_gl))
240 //LYXERR("Messages: language(" << l << ") in dir(" << dir << ")");
242 string const locale_dir = package().locale_dir().toFilesystemEncoding();
243 cat_gl = mssg_gl.open(PACKAGE, loc_gl, locale_dir.c_str());
249 mssg_gl.close(cat_gl);
252 docstring const get(string const & msg) const
254 return mssg_gl.get(cat_gl, 0, 0, msg);
262 messages<char> const & mssg_gl;