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 for `" << m << "'.");
164 trans = from_ascii(m);
165 } else if (trans_c == m_c) {
166 //LYXERR(Debug::LOCALE, "Same as entered returned");
167 trans = from_ascii(m);
169 //LYXERR(Debug::LOCALE, "We got a translation");
170 // m is actually not a char const * but ucs4 data
171 trans = reinterpret_cast<char_type const *>(trans_c);
174 cleanTranslation(trans);
176 // Reset environment variables as they were.
177 if (!lang_.empty()) {
178 // Reset everything as it was.
179 LYXERR(Debug::LOCALE, "restoring LANGUAGE from "
180 << getEnv("LANGUAGE")
181 << " to " << oldLANGUAGE);
182 if (!setEnv("LANGUAGE", oldLANGUAGE))
183 LYXERR(Debug::LOCALE, "\t... failed!");
184 LYXERR(Debug::LOCALE, "restoring LC_ALL from " << getEnv("LC_ALL")
185 << " to " << oldLC_ALL);
186 if (!setEnv("LC_ALL", oldLC_ALL))
187 LYXERR(Debug::LOCALE, "\t... failed!");
188 #ifdef HAVE_LC_MESSAGES
189 setlocale(LC_MESSAGES, "");
193 pair<TranslationCache::iterator, bool> result =
194 cache_.insert(make_pair(m, trans));
196 LASSERT(result.second, /**/);
198 return result.first->second;
204 // This is the dummy variant.
208 Messages::Messages(string const & /* l */) {}
210 void Messages::init()
215 docstring const Messages::get(string const & m) const
217 docstring trans = from_ascii(m);
218 cleanTranslation(trans);
232 // This version of the Pimpl utilizes the message capability of
233 // libstdc++ that is distributed with GNU G++.
234 class Messages::Pimpl {
236 typedef messages<char>::catalog catalog;
238 Pimpl(string const & l)
240 loc_gl(lang_.c_str()),
241 mssg_gl(use_facet<messages<char> >(loc_gl))
243 //LYXERR("Messages: language(" << l << ") in dir(" << dir << ")");
245 string const locale_dir = package().locale_dir().toFilesystemEncoding();
246 cat_gl = mssg_gl.open(PACKAGE, loc_gl, locale_dir.c_str());
252 mssg_gl.close(cat_gl);
255 docstring const get(string const & msg) const
257 return mssg_gl.get(cat_gl, 0, 0, msg);
265 messages<char> const & mssg_gl;