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"
25 # define N_(str) (str) // for marking strings to be translated
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']]". Also,
38 when placeholders are used, the context can indicate what will
39 be substituted for the placeholder (e.g. "%1$s[[date]], %1$s
40 [[time]]). This means that we need to filter out everything
41 in double square brackets at the end of the string, otherwise
42 the user sees bogus messages. If we are unable to honour the
43 request we just return what we got in.
45 static docstring const ctx_start = from_ascii("[[");
46 static docstring const ctx_end = from_ascii("]]");
48 size_t const pos1 = trans.find(ctx_start);
49 if (pos1 != docstring::npos) {
50 size_t const pos2 = trans.find(ctx_end, pos1);
51 if (pos2 != docstring::npos) {
52 trans.erase(pos1, pos2 - pos1 + 2);
70 # include <libintl.h> // use the header already in the system *EK*
72 # include "intl/libintl.h"
75 using namespace lyx::support;
79 // This version use the traditional gettext.
80 Messages::Messages(string const & l)
83 // strip off any encoding suffix, i.e., assume 8-bit po files
84 size_t i = lang_.find(".");
85 lang_ = lang_.substr(0, i);
86 LYXERR(Debug::LOCALE, "language(" << lang_ << ")");
93 string const locale_dir = package().locale_dir().toFilesystemEncoding();
94 char const * c = bindtextdomain(PACKAGE, locale_dir.c_str());
97 LYXERR(Debug::LOCALE, "Error code: " << errno << '\n'
98 << "Directory : " << package().locale_dir().absFileName() << '\n'
99 << "Rtn value : " << c);
102 if (!bind_textdomain_codeset(PACKAGE, ucs4_codeset)) {
103 LYXERR(Debug::LOCALE, "Error code: " << errno << '\n'
104 << "Codeset : " << ucs4_codeset);
111 string Messages::language() const
113 // get the language from the gmo file
114 string const test = N_("[[Replace with the code of your language]]");
115 string const trans = to_utf8(get(test));
117 LYXERR0("Something is weird.");
124 bool Messages::available(string const & c)
126 static string locale_dir = package().locale_dir().toFilesystemEncoding();
128 // this loops at most twice
130 string const filen = locale_dir + "/" + code
131 + "/LC_MESSAGES/" PACKAGE ".mo";
132 if (FileName(filen).isReadableFile())
134 if (contains(code, '_'))
135 code = token(code, '_', 0);
144 // Trivial wrapper around gettext()
145 docstring const getText(string const & m)
147 // FIXME: gettext sometimes "forgets" the ucs4_codeset we set
148 // in init(), which leads to severe message corruption (#7371)
149 // We set it again here unconditionally. A real fix must be found!
150 LATTEST(bind_textdomain_codeset(PACKAGE, ucs4_codeset));
152 char const * m_c = m.c_str();
153 char const * trans_c = gettext(m_c);
156 LYXERR(Debug::LOCALE, "Undefined result from gettext for `" << m << "'.");
157 trans = from_ascii(m);
158 } else if (trans_c == m_c) {
159 //LYXERR(Debug::LOCALE, "Same as entered returned");
160 trans = from_ascii(m);
162 //LYXERR(Debug::LOCALE, "We got a translation");
163 // m is actually not a char const * but ucs4 data
164 trans = reinterpret_cast<char_type const *>(trans_c);
167 cleanTranslation(trans);
175 docstring const Messages::get(string const & m) const
180 // Look for the translated string in the cache.
181 TranslationCache::iterator it = cache_.find(m);
182 if (it != cache_.end())
185 // The string was not found, use gettext to generate it
187 if (!lang_.empty()) {
188 // This GNU extension overrides any language locale
190 LYXERR(Debug::LOCALE, "Setting LANGUAGE to " << lang_);
191 EnvChanger language_chg("LANGUAGE", lang_);
192 // However, setting LANGUAGE does nothing when the
193 // locale is "C". Therefore we set the locale to
194 // something that is believed to exist on most
195 // systems. The idea is that one should be able to
196 // load German documents even without having de_DE
198 LYXERR(Debug::LOCALE, "Setting LC_ALL to en_US");
199 EnvChanger lc_all_chg("LC_ALL", "en_US");
200 #ifdef HAVE_LC_MESSAGES
201 setlocale(LC_MESSAGES, "");
208 #ifdef HAVE_LC_MESSAGES
209 setlocale(LC_MESSAGES, "");
212 // store translation in cache
213 pair<TranslationCache::iterator, bool> result =
214 cache_.insert(make_pair(m, trans));
216 LASSERT(result.second, return from_utf8(m));
218 return result.first->second;
224 // This is the dummy variant.
228 Messages::Messages(string const & /* l */) {}
230 void Messages::init()
235 docstring const Messages::get(string const & m) const
237 docstring trans = from_ascii(m);
238 cleanTranslation(trans);
242 std::string Messages::language() const
247 bool Messages::available(string const & /* c */)