Skip to content

Commit

Permalink
#5231: Make the preference page and the language setting persistence …
Browse files Browse the repository at this point in the history
…work again
  • Loading branch information
codereader committed Aug 15, 2020
1 parent 2ef05aa commit 9f917c9
Show file tree
Hide file tree
Showing 6 changed files with 172 additions and 74 deletions.
5 changes: 5 additions & 0 deletions include/i18n.h
Expand Up @@ -28,6 +28,11 @@ class ILanguageManager
*/
virtual void registerProvider(const ILocalisationProvider::Ptr& instance) = 0;

/**
* Removes references to the localisation provider.
*/
virtual void clearProvider() = 0;

/**
* Returns the localised version of the given input string
* or the unmodified string if no suitable localisation provider
Expand Down
179 changes: 119 additions & 60 deletions radiant/LocalisationProvider.cpp
Expand Up @@ -9,6 +9,7 @@

#include "string/case_conv.h"
#include "os/path.h"
#include "module/StaticModule.h"

#include <wx/translation.h>

Expand Down Expand Up @@ -54,75 +55,26 @@ LocalisationProvider::LocalisationProvider(ApplicationContext& ctx)
_wxLocale->AddCatalog(GETTEXT_PACKAGE);
}

std::string LocalisationProvider::getLocalisedString(const char* stringToLocalise)
std::shared_ptr<LocalisationProvider>& LocalisationProvider::Instance()
{
return wxGetTranslation(stringToLocalise).ToStdString();
static std::shared_ptr<LocalisationProvider> _instancePtr;
return _instancePtr;
}

#if 0
void LocalisationProvider::initialiseModule(const ApplicationContext& ctx)
void LocalisationProvider::Initialise(ApplicationContext& context)
{
rMessage() << getName() << "::initialiseModule called" << std::endl;

int curLangIndex = 0; // english

try
{
int index = getLanguageIndex(_curLanguage);

// Get the offset into the array of available languages
auto found = std::find(_availableLanguages.begin(), _availableLanguages.end(), index);

if (found != _availableLanguages.end())
{
curLangIndex = static_cast<int>(std::distance(_availableLanguages.begin(), found));
}
}
catch (UnknownLanguageException&)
{
rWarning() << "Warning, unknown language found in " <<
LANGUAGE_SETTING_FILE << ", reverting to English" << std::endl;
}

// Construct the list of available languages
ComboBoxValueList langs;

for (int code : _availableLanguages)
{
const Language& lang = _supportedLanguages[code];
langs.emplace_back(lang.twoDigitCode + " - " + lang.displayName);
}

// Load the currently selected index into the registry
registry::setValue(RKEY_LANGUAGE, curLangIndex);
GlobalRegistry().setAttribute(RKEY_LANGUAGE, "volatile", "1"); // don't save this to user.xml

// Add Preferences
IPreferencePage& page = GlobalPreferenceSystem().getPage(_("Settings/Language"));
page.appendCombo(_("Language"), RKEY_LANGUAGE, langs);

page.appendLabel(_("<b>Note:</b> You'll need to restart DarkRadiant\nafter changing the language setting."));
Instance().reset(new LocalisationProvider(context));
}
#endif

#if 0
void LocalisationProvider::shutdownModule()
void LocalisationProvider::Cleanup()
{
// Get the language setting from the registry (this is an integer)
// and look up the language code (two digit)
int langNum = registry::getValue<int>(RKEY_LANGUAGE);

assert(langNum >= 0 && langNum < static_cast<int>(_availableLanguages.size()));

// Look up the language index in the list of available languages
int langIndex = _availableLanguages[langNum];

assert(_supportedLanguages.find(langIndex) != _supportedLanguages.end());
Instance().reset();
}

// Save the language code to the settings file
saveLanguageSetting(_supportedLanguages[langIndex].twoDigitCode);
std::string LocalisationProvider::getLocalisedString(const char* stringToLocalise)
{
return wxGetTranslation(stringToLocalise).ToStdString();
}
#endif

std::string LocalisationProvider::loadLanguageSetting()
{
Expand All @@ -149,6 +101,40 @@ void LocalisationProvider::saveLanguageSetting(const std::string& language)
str.close();
}

void LocalisationProvider::foreachAvailableLanguage(const std::function<void(const Language&)>& functor)
{
for (int code : _availableLanguages)
{
functor(_supportedLanguages[code]);
}
}

int LocalisationProvider::getCurrentLanguageIndex() const
{
// Set up the indices
int curLanguageIndex = 0; // english

try
{
int index = LocalisationProvider::Instance()->getLanguageIndex(_curLanguage);

// Get the offset into the array of available languages
auto found = std::find(_availableLanguages.begin(), _availableLanguages.end(), index);

if (found != _availableLanguages.end())
{
curLanguageIndex = static_cast<int>(std::distance(_availableLanguages.begin(), found));
}
}
catch (UnknownLanguageException&)
{
rWarning() << "Warning, unknown language found in " <<
LANGUAGE_SETTING_FILE << ", reverting to English" << std::endl;
}

return curLanguageIndex;
}

void LocalisationProvider::loadSupportedLanguages()
{
_supportedLanguages.clear();
Expand Down Expand Up @@ -201,4 +187,77 @@ int LocalisationProvider::getLanguageIndex(const std::string& languageCode)
throw UnknownLanguageException("Unknown language: " + languageCode);
}

void LocalisationProvider::saveLanguageSetting()
{
// Get the language setting from the registry (this is an integer)
// and look up the language code (two digit)
int langNum = registry::getValue<int>(RKEY_LANGUAGE);

assert(langNum >= 0 && langNum < static_cast<int>(_availableLanguages.size()));

// Look up the language index in the list of available languages
int langIndex = _availableLanguages[langNum];

assert(_supportedLanguages.find(langIndex) != _supportedLanguages.end());

// Save the language code to the settings file
saveLanguageSetting(_supportedLanguages[langIndex].twoDigitCode);
}

// Localisation module, taking care of the Preferences page

class LocalisationModule :
public RegisterableModule
{
public:
const std::string& getName() const override
{
static std::string _name("LocalisationModule");
return _name;
}

const StringSet& getDependencies() const override
{
static StringSet _dependencies;

if (_dependencies.empty())
{
_dependencies.insert(MODULE_PREFERENCESYSTEM);
_dependencies.insert(MODULE_XMLREGISTRY);
}

return _dependencies;
}

void initialiseModule(const ApplicationContext& ctx) override
{
rMessage() << getName() << "::initialiseModule called" << std::endl;

// Construct the list of available languages
ComboBoxValueList langs;

LocalisationProvider::Instance()->foreachAvailableLanguage([&](const LocalisationProvider::Language& lang)
{
langs.emplace_back(lang.twoDigitCode + " - " + lang.displayName);
});

// Load the currently selected index into the registry
registry::setValue(RKEY_LANGUAGE, LocalisationProvider::Instance()->getCurrentLanguageIndex());
GlobalRegistry().setAttribute(RKEY_LANGUAGE, "volatile", "1"); // don't save this to user.xml

// Add Preferences
IPreferencePage& page = GlobalPreferenceSystem().getPage(_("Settings/Language"));
page.appendCombo(_("Language"), RKEY_LANGUAGE, langs);

page.appendLabel(_("<b>Note:</b> You'll need to restart DarkRadiant\nafter changing the language setting."));
}

void shutdownModule()
{
LocalisationProvider::Instance()->saveLanguageSetting();
}
};

module::StaticModule<LocalisationModule> localisationModule;

}
45 changes: 33 additions & 12 deletions radiant/LocalisationProvider.h
Expand Up @@ -10,16 +10,7 @@ namespace ui
class LocalisationProvider :
public language::ILocalisationProvider
{
private:
// The current language string (e.g. "en_US")
std::string _curLanguage;
std::string _languageSettingFile;

// The path where all the languages are stored
std::string _i18nPath;

std::unique_ptr<wxLocale> _wxLocale;

public:
struct Language
{
std::string twoDigitCode; // "en"
Expand All @@ -34,6 +25,18 @@ class LocalisationProvider :
{}
};

private:
// The current language string (e.g. "en_US")
std::string _curLanguage;
int _curLanguageIndex;

std::string _languageSettingFile;

// The path where all the languages are stored
std::string _i18nPath;

std::unique_ptr<wxLocale> _wxLocale;

// Supported languages
typedef std::map<int, Language> LanguageMap;
LanguageMap _supportedLanguages;
Expand All @@ -42,18 +45,36 @@ class LocalisationProvider :
typedef std::vector<int> LanguageList;
LanguageList _availableLanguages;

public:
LocalisationProvider(ApplicationContext& context);
LocalisationProvider(const LocalisationProvider& other) = delete;

public:
std::string getLocalisedString(const char* stringToLocalise) override;

void foreachAvailableLanguage(const std::function<void(const Language&)>& functor);

// The currently selected language, as index into the list of available languages
int getCurrentLanguageIndex() const;

// Persists the current language selection to the file on disk
void saveLanguageSetting();

// Singleton instance setting up the shared collections
static std::shared_ptr<LocalisationProvider>& Instance();

// Sets up available and supported language collections
static void Initialise(ApplicationContext& context);

// Cleans up shared static resources allocated at startup
static void Cleanup();

private:
// Loads the language setting from the .language in the user settings folder
std::string loadLanguageSetting();

// Saves the language setting to the .language in the user settings folder
void saveLanguageSetting(const std::string& language);

// Fills the array of supported languages
void loadSupportedLanguages();

Expand Down
10 changes: 8 additions & 2 deletions radiant/RadiantApp.cpp
Expand Up @@ -67,8 +67,8 @@ bool RadiantApp::OnInit()
}

// Register the localisation helper before initialising the modules
auto& languageManager = _coreModule->get()->getLanguageManager();
languageManager.registerProvider(std::make_shared<ui::LocalisationProvider>(_context));
ui::LocalisationProvider::Initialise(_context);
_coreModule->get()->getLanguageManager().registerProvider(ui::LocalisationProvider::Instance());

#if defined(POSIX) && !defined(__APPLE__)
// greebo: not sure if this is needed
Expand Down Expand Up @@ -101,6 +101,12 @@ int RadiantApp::OnExit()
// Issue a shutdown() call to all the modules
module::GlobalModuleRegistry().shutdownModules();

auto& languageManager = _coreModule->get()->getLanguageManager();
languageManager.clearProvider();

// Clean up static resources
ui::LocalisationProvider::Cleanup();

_coreModule.reset();

return wxApp::OnExit();
Expand Down
5 changes: 5 additions & 0 deletions radiantcore/settings/LanguageManager.cpp
Expand Up @@ -10,6 +10,11 @@ void LanguageManager::registerProvider(const ILocalisationProvider::Ptr& instanc
_provider = instance;
}

void LanguageManager::clearProvider()
{
_provider.reset();
}

std::string LanguageManager::getLocalisedString(const char* stringToLocalise)
{
return _provider ? _provider->getLocalisedString(stringToLocalise) : stringToLocalise;
Expand Down
2 changes: 2 additions & 0 deletions radiantcore/settings/LanguageManager.h
Expand Up @@ -20,6 +20,8 @@ class LanguageManager :
public:
void registerProvider(const ILocalisationProvider::Ptr& instance) override;

void clearProvider() override;

std::string getLocalisedString(const char* stringToLocalise) override;
};

Expand Down

0 comments on commit 9f917c9

Please sign in to comment.