mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-12-22 13:18:28 +00:00
Fix bug #7741: incorrect locale when starting R from LyX?
The goal here is to get rid of the old code that modified variables LANGUAGE and LC_ALL, therefore creating the problems mentionned in the ticket. In the new system, there is no explicit "GUI" message handler, that needs to be reset at each language change. Instead, getGuiMessages calls getMessages with the correct parameter. This allows to simplify greatly the code and to remove a lot of old cruft.
This commit is contained in:
parent
f6b1c24b99
commit
16fd47ad8f
46
src/LyX.cpp
46
src/LyX.cpp
@ -141,10 +141,6 @@ struct LyX::Impl
|
||||
{
|
||||
Impl() : spell_checker_(0), apple_spell_checker_(0), aspell_checker_(0), enchant_checker_(0), hunspell_checker_(0)
|
||||
{
|
||||
// Set the default User Interface language as soon as possible.
|
||||
// The language used will be derived from the environment
|
||||
// variables.
|
||||
messages_["GUI"] = Messages();
|
||||
}
|
||||
|
||||
~Impl()
|
||||
@ -265,25 +261,6 @@ Messages & LyX::messages(string const & language)
|
||||
}
|
||||
|
||||
|
||||
void setRcGuiLanguage()
|
||||
{
|
||||
LASSERT(singleton_, /**/);
|
||||
if (lyxrc.gui_language == "auto")
|
||||
return;
|
||||
Language const * language = languages.getLanguage(lyxrc.gui_language);
|
||||
if (language) {
|
||||
LYXERR(Debug::LOCALE, "Setting LANGUAGE to " << language->code());
|
||||
if (!setEnv("LANGUAGE", language->code()))
|
||||
LYXERR(Debug::LOCALE, "\t... failed!");
|
||||
}
|
||||
LYXERR(Debug::LOCALE, "Setting LC_ALL to en_US");
|
||||
if (!setEnv("LC_ALL", "en_US"))
|
||||
LYXERR(Debug::LOCALE, "\t... failed!");
|
||||
Messages::init();
|
||||
singleton_->pimpl_->messages_["GUI"] = Messages();
|
||||
}
|
||||
|
||||
|
||||
int LyX::exec(int & argc, char * argv[])
|
||||
{
|
||||
// Minimal setting of locale before parsing command line
|
||||
@ -753,9 +730,6 @@ bool LyX::init()
|
||||
if (!readRcFile("lyxrc.dist"))
|
||||
return false;
|
||||
|
||||
// Set the language defined by the distributor.
|
||||
setRcGuiLanguage();
|
||||
|
||||
// Set the PATH correctly.
|
||||
#if !defined (USE_POSIX_PACKAGING)
|
||||
// Add the directory containing the LyX executable to the path
|
||||
@ -796,9 +770,6 @@ bool LyX::init()
|
||||
// Read lyxrc.dist again to be able to override viewer auto-detection.
|
||||
readRcFile("lyxrc.dist");
|
||||
|
||||
// Set again the language defined by the distributor.
|
||||
setRcGuiLanguage();
|
||||
|
||||
system_lyxrc = lyxrc;
|
||||
system_formats = formats;
|
||||
pimpl_->system_converters_ = pimpl_->converters_;
|
||||
@ -814,9 +785,6 @@ bool LyX::init()
|
||||
if (!readLanguagesFile("languages"))
|
||||
return false;
|
||||
|
||||
// Set the language defined by the user.
|
||||
setRcGuiLanguage();
|
||||
|
||||
LYXERR(Debug::INIT, "Reading layouts...");
|
||||
// Load the layouts
|
||||
LayoutFileList::get().read();
|
||||
@ -1396,7 +1364,19 @@ Messages const & getMessages(string const & language)
|
||||
Messages const & getGuiMessages()
|
||||
{
|
||||
LASSERT(singleton_, /**/);
|
||||
return singleton_->pimpl_->messages_["GUI"];
|
||||
// A cache to translate full language name to language code
|
||||
static string last_language = "auto";
|
||||
static string code;
|
||||
if (lyxrc.gui_language != last_language) {
|
||||
if (lyxrc.gui_language == "auto")
|
||||
code.clear();
|
||||
else {
|
||||
Language const * l = languages.getLanguage(lyxrc.gui_language);
|
||||
code = l ? l->code() : string();
|
||||
}
|
||||
last_language = lyxrc.gui_language;
|
||||
}
|
||||
return singleton_->messages(code);
|
||||
}
|
||||
|
||||
|
||||
|
@ -151,7 +151,6 @@ private:
|
||||
friend CmdDef & theTopLevelCmdDef();
|
||||
friend SpellChecker * theSpellChecker();
|
||||
friend void setSpellChecker();
|
||||
friend void setRcGuiLanguage();
|
||||
friend void emergencyCleanup();
|
||||
friend void execBatchCommands();
|
||||
friend void lyx_exit(int exit_code);
|
||||
@ -164,8 +163,6 @@ void emergencyCleanup();
|
||||
/// \p exit_code is 0 by default, if a non zero value is passed,
|
||||
/// emergencyCleanup() will be called before exiting.
|
||||
void lyx_exit(int exit_code);
|
||||
/// Set the language defined by the user.
|
||||
void setRcGuiLanguage();
|
||||
/// Execute batch commands if available.
|
||||
void execBatchCommands();
|
||||
|
||||
|
@ -29,9 +29,7 @@ endif
|
||||
|
||||
SOURCEFILES = \
|
||||
boost.cpp \
|
||||
client.cpp \
|
||||
gettext.cpp \
|
||||
Messages.cpp
|
||||
client.cpp
|
||||
|
||||
HEADERFILES = \
|
||||
Messages.h
|
||||
|
@ -1,190 +0,0 @@
|
||||
/* \file Messages.cpp
|
||||
* This file is part of LyX, the document processor.
|
||||
* Licence details can be found in the file COPYING.
|
||||
*
|
||||
* \author Lars Gullik Bjønnes
|
||||
*
|
||||
* Full author contact details are available in file CREDITS.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "Messages.h"
|
||||
#include "support/debug.h"
|
||||
#include "support/filetools.h"
|
||||
#include "support/Package.h"
|
||||
#include "support/unicode.h"
|
||||
|
||||
#include <cerrno>
|
||||
#include <ostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace lyx::support;
|
||||
|
||||
namespace lyx {
|
||||
|
||||
|
||||
#ifdef ENABLE_NLS
|
||||
|
||||
#if 0
|
||||
|
||||
#include <locale>
|
||||
|
||||
// This version of the Pimpl utilizes the message capability of
|
||||
// libstdc++ that is distributed with GNU G++.
|
||||
class Messages::Pimpl {
|
||||
public:
|
||||
typedef messages<char>::catalog catalog;
|
||||
|
||||
Pimpl(string const & l)
|
||||
: lang_(l),
|
||||
loc_gl(lang_.c_str()),
|
||||
mssg_gl(use_facet<messages<char> >(loc_gl))
|
||||
{
|
||||
//lyxerr << "Messages: language(" << l
|
||||
// << ") in dir(" << dir << ")" << endl;
|
||||
|
||||
string const locale_dir = package().locale_dir().toFilesystemEncoding();
|
||||
cat_gl = mssg_gl.open(PACKAGE, loc_gl, locale_dir.c_str());
|
||||
|
||||
}
|
||||
|
||||
~Pimpl()
|
||||
{
|
||||
mssg_gl.close(cat_gl);
|
||||
}
|
||||
|
||||
string const get(string const & msg) const
|
||||
{
|
||||
return mssg_gl.get(cat_gl, 0, 0, msg);
|
||||
}
|
||||
private:
|
||||
///
|
||||
string lang_;
|
||||
///
|
||||
locale loc_gl;
|
||||
///
|
||||
messages<char> const & mssg_gl;
|
||||
///
|
||||
catalog cat_gl;
|
||||
};
|
||||
#else
|
||||
|
||||
#ifdef HAVE_LOCALE_H
|
||||
# include <locale.h>
|
||||
#endif
|
||||
|
||||
# if HAVE_GETTEXT
|
||||
# include <libintl.h> // use the header already in the system *EK*
|
||||
# else
|
||||
# include "intl/libintl.h"
|
||||
# endif
|
||||
|
||||
// This is a more traditional variant.
|
||||
class Messages::Pimpl {
|
||||
public:
|
||||
Pimpl(string const & l)
|
||||
: lang_(l)
|
||||
{
|
||||
//lyxerr << "Messages: language(" << l
|
||||
// << ") in dir(" << dir << ")" << endl;
|
||||
|
||||
}
|
||||
|
||||
~Pimpl() {}
|
||||
|
||||
docstring const get(string const & m) const
|
||||
{
|
||||
if (m.empty())
|
||||
return from_ascii(m);
|
||||
|
||||
char * o = setlocale(LC_ALL, 0);
|
||||
string old;
|
||||
if (o)
|
||||
old = o;
|
||||
char * n = setlocale(LC_ALL, lang_.c_str());
|
||||
if (!n)
|
||||
// If we are unable to honour the request we just
|
||||
// return what we got in.
|
||||
return from_ascii(m);
|
||||
errno = 0;
|
||||
string const locale_dir = package().locale_dir().toFilesystemEncoding();
|
||||
char const * c = bindtextdomain(PACKAGE, locale_dir.c_str());
|
||||
int e = errno;
|
||||
if (e) {
|
||||
LYXERR(Debug::DEBUG, "Messages::get()" << '\n'
|
||||
<< "Error code: " << errno << '\n'
|
||||
<< "Lang, mess: " << lang_ << " " << m << '\n'
|
||||
<< "Directory : " << package().locale_dir().absFileName() << '\n'
|
||||
<< "Rtn value : " << c);
|
||||
}
|
||||
|
||||
if (!bind_textdomain_codeset(PACKAGE, ucs4_codeset)) {
|
||||
LYXERR(Debug::DEBUG, "Messages::get()" << '\n'
|
||||
<< "Error code: " << errno << '\n'
|
||||
<< "Codeset : " << ucs4_codeset << '\n');
|
||||
}
|
||||
|
||||
textdomain(PACKAGE);
|
||||
|
||||
char const * tmp = m.c_str();
|
||||
char const * msg = gettext(tmp);
|
||||
docstring translated;
|
||||
if (!msg) {
|
||||
lyxerr << "Undefined result from gettext" << endl;
|
||||
translated = from_ascii(tmp);
|
||||
} else if (msg == tmp) {
|
||||
//lyxerr << "Same as entered returned" << endl;
|
||||
translated = from_ascii(tmp);
|
||||
} else {
|
||||
LYXERR(Debug::DEBUG, "We got a translation");
|
||||
char_type const * ucs4 = reinterpret_cast<char_type const *>(msg);
|
||||
translated = ucs4;
|
||||
}
|
||||
setlocale(LC_ALL, old.c_str());
|
||||
return translated;
|
||||
}
|
||||
private:
|
||||
///
|
||||
string lang_;
|
||||
};
|
||||
#endif
|
||||
|
||||
#else // ENABLE_NLS
|
||||
// This is the dummy variant.
|
||||
class Messages::Pimpl {
|
||||
public:
|
||||
Pimpl(string const &) {}
|
||||
|
||||
~Pimpl() {}
|
||||
|
||||
docstring const get(string const & m) const
|
||||
{
|
||||
return from_ascii(m);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
Messages::Messages()
|
||||
: pimpl_(new Pimpl(""))
|
||||
{}
|
||||
|
||||
|
||||
Messages::Messages(string const & l)
|
||||
: pimpl_(new Pimpl(l))
|
||||
{}
|
||||
|
||||
|
||||
// We need this for the sake of scoped_ptr
|
||||
Messages::~Messages()
|
||||
{}
|
||||
|
||||
|
||||
docstring const Messages::get(string const & msg) const
|
||||
{
|
||||
return pimpl_->get(msg);
|
||||
}
|
||||
|
||||
|
||||
} // namespace lyx
|
@ -1,40 +0,0 @@
|
||||
// -*- C++ -*-
|
||||
/* \file Messages.h
|
||||
* This file is part of LyX, the document processor.
|
||||
* Licence details can be found in the file COPYING.
|
||||
*
|
||||
* \author Lars Gullik Bjønnes
|
||||
*
|
||||
* Full author contact details are available in file CREDITS.
|
||||
*/
|
||||
|
||||
#ifndef MESSAGES_H
|
||||
#define MESSAGES_H
|
||||
|
||||
#include "support/docstring.h"
|
||||
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
|
||||
namespace lyx {
|
||||
|
||||
///
|
||||
class Messages {
|
||||
public:
|
||||
///
|
||||
Messages();
|
||||
///
|
||||
Messages(std::string const & l);
|
||||
///
|
||||
~Messages();
|
||||
///
|
||||
docstring const get(std::string const & msg) const;
|
||||
private:
|
||||
class Pimpl;
|
||||
::boost::scoped_ptr<Pimpl> pimpl_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace lyx
|
||||
|
||||
#endif
|
@ -16,6 +16,7 @@
|
||||
#include "support/FileName.h"
|
||||
#include "support/FileNameList.h"
|
||||
#include "support/lstrings.h"
|
||||
#include "support/Messages.h"
|
||||
#include "support/unicode.h"
|
||||
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
@ -74,6 +75,21 @@ struct LyXRC {
|
||||
void lyx_exit(int)
|
||||
{}
|
||||
|
||||
// Dummy language support
|
||||
Messages const & getGuiMessages()
|
||||
{
|
||||
static Messages lyx_messages;
|
||||
|
||||
return lyx_messages;
|
||||
}
|
||||
|
||||
|
||||
Messages const & getMessages(string const &)
|
||||
{
|
||||
return getGuiMessages();
|
||||
}
|
||||
|
||||
|
||||
namespace support {
|
||||
|
||||
string itoa(unsigned int i)
|
||||
|
@ -1,66 +0,0 @@
|
||||
/**
|
||||
* \file src/gettext.cpp
|
||||
* This file is part of LyX, the document processor.
|
||||
* Licence details can be found in the file COPYING.
|
||||
*
|
||||
* \author Lars Gullik Bjønnes
|
||||
* \author Jean-Marc Lasgouttes
|
||||
*
|
||||
* Full author contact details are available in file CREDITS.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "support/gettext.h"
|
||||
#include "Messages.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace lyx {
|
||||
|
||||
|
||||
#ifdef HAVE_LOCALE_H
|
||||
# include <locale.h>
|
||||
#endif
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
Messages const & getLyXMessages()
|
||||
{
|
||||
static Messages lyx_messages;
|
||||
|
||||
return lyx_messages;
|
||||
}
|
||||
|
||||
} // anon namespace
|
||||
|
||||
|
||||
docstring const _(string const & str)
|
||||
{
|
||||
return getLyXMessages().get(str);
|
||||
}
|
||||
|
||||
|
||||
#ifdef ENABLE_NLS
|
||||
|
||||
void locale_init()
|
||||
{
|
||||
# ifdef HAVE_LC_MESSAGES
|
||||
setlocale(LC_MESSAGES, "");
|
||||
# endif
|
||||
setlocale(LC_CTYPE, "");
|
||||
setlocale(LC_NUMERIC, "C");
|
||||
}
|
||||
|
||||
#else // ENABLE_NLS
|
||||
|
||||
void locale_init()
|
||||
{
|
||||
setlocale(LC_NUMERIC, "C");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
} // namespace lyx
|
@ -1995,10 +1995,7 @@ void GuiApplication::exit(int status)
|
||||
|
||||
void GuiApplication::setGuiLanguage()
|
||||
{
|
||||
// Set the language defined by the user.
|
||||
setRcGuiLanguage();
|
||||
|
||||
QString const default_language = toqstr(Messages::defaultLanguage());
|
||||
QString const default_language = toqstr(getGuiMessages().language());
|
||||
LYXERR(Debug::LOCALE, "Trying to set default locale to: " << default_language);
|
||||
QLocale const default_locale(default_language);
|
||||
QLocale::setDefault(default_locale);
|
||||
|
@ -22,19 +22,18 @@
|
||||
|
||||
#include <cerrno>
|
||||
|
||||
# define N_(str) (str) // for marking strings to be translated
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace lyx {
|
||||
|
||||
// Instanciate static member.
|
||||
string Messages::main_lang_;
|
||||
|
||||
void cleanTranslation(docstring & trans)
|
||||
{
|
||||
/*
|
||||
Some english words have different translations, depending on
|
||||
context. In these cases the original string is augmented by
|
||||
context information (e.g. "To:[[as in 'From page x to page
|
||||
context information (e.g. "To:[[[as in 'From page x to page
|
||||
y']]" and "To:[[as in 'From format x to format y']]". This
|
||||
means that we need to filter out everything in double square
|
||||
brackets at the end of the string, otherwise the user sees
|
||||
@ -68,22 +67,6 @@ using namespace lyx::support;
|
||||
|
||||
namespace lyx {
|
||||
|
||||
void Messages::setDefaultLanguage()
|
||||
{
|
||||
char const * env_lang[5] = {"LANGUAGE", "LC_ALL", "LC_MESSAGES",
|
||||
"LC_MESSAGE", "LANG"};
|
||||
for (size_t i = 0; i != 5; ++i) {
|
||||
string const lang = getEnv(env_lang[i]);
|
||||
if (lang.empty())
|
||||
continue;
|
||||
Messages::main_lang_ = lang;
|
||||
return;
|
||||
}
|
||||
// Not found!
|
||||
LYXERR(Debug::LOCALE, "Default language not found!");
|
||||
}
|
||||
|
||||
|
||||
// This version use the traditional gettext.
|
||||
Messages::Messages(string const & l)
|
||||
: lang_(l), warned_(false)
|
||||
@ -113,17 +96,25 @@ void Messages::init()
|
||||
}
|
||||
|
||||
textdomain(PACKAGE);
|
||||
}
|
||||
|
||||
// Reset default language;
|
||||
setDefaultLanguage();
|
||||
|
||||
string Messages::language() const
|
||||
{
|
||||
// get the language from the gmo file
|
||||
string const test = N_("[[Replace with the code of your language]]");
|
||||
string const trans = to_utf8(get(test));
|
||||
if (trans == test) {
|
||||
LYXERR0("Something is weird.");
|
||||
return string();
|
||||
} else
|
||||
return trans;
|
||||
}
|
||||
|
||||
|
||||
bool Messages::available() const
|
||||
{
|
||||
string const test = languageTestString();
|
||||
string const trans = to_utf8(get(test));
|
||||
return !trans.empty() && trans != test;
|
||||
return !language().empty();
|
||||
}
|
||||
|
||||
|
||||
|
@ -26,18 +26,14 @@ public:
|
||||
Messages(std::string const & l = std::string());
|
||||
///
|
||||
docstring const get(std::string const & msg) const;
|
||||
/// What is the language associated with this translation?
|
||||
std::string language() const;
|
||||
/// Is an (at least partial) translation of this language available?
|
||||
bool available() const;
|
||||
///
|
||||
static void init();
|
||||
///
|
||||
static std::string const & defaultLanguage() { return main_lang_; }
|
||||
|
||||
private:
|
||||
///
|
||||
static void setDefaultLanguage();
|
||||
///
|
||||
static std::string main_lang_;
|
||||
///
|
||||
std::string lang_;
|
||||
/// Did we warn about unavailable locale already?
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "support/gettext.h"
|
||||
#include "support/lstrings.h"
|
||||
#include "support/os.h"
|
||||
#include "support/Messages.h"
|
||||
#include "support/Package.h"
|
||||
#include "support/Path.h"
|
||||
#include "support/Systemcall.h"
|
||||
@ -282,7 +283,7 @@ FileName const i18nLibFileSearch(string const & dir, string const & name,
|
||||
each po file is able to tell us its name. (JMarc)
|
||||
*/
|
||||
|
||||
string lang = to_ascii(_(languageTestString()));
|
||||
string lang = getGuiMessages().language();
|
||||
string const language = getEnv("LANGUAGE");
|
||||
if (!lang.empty() && !language.empty())
|
||||
lang = language;
|
||||
|
@ -1296,12 +1296,6 @@ int findToken(char const * const str[], string const & search_token)
|
||||
}
|
||||
|
||||
|
||||
string const languageTestString()
|
||||
{
|
||||
return N_("[[Replace with the code of your language]]");
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
docstring bformat(docstring const & fmt, int arg1)
|
||||
{
|
||||
|
@ -285,9 +285,6 @@ docstring const getStringFromVector(std::vector<docstring> const & vec,
|
||||
/// found, else -1. The last item in \p str must be "".
|
||||
int findToken(char const * const str[], std::string const & search_token);
|
||||
|
||||
/// A test string that is supposed to be translated into the gettext code
|
||||
std::string const languageTestString();
|
||||
|
||||
template <class Arg1>
|
||||
docstring bformat(docstring const & fmt, Arg1);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user