Redesign AegisubLocale

Use wxTranslations directly rather than going through wxLocale. This
significantly simplifies the code, eliminates the hardcoded list of
languages for non-windows, and makes it possible to use mismatched
languages and locales.

Closes #1508.
This commit is contained in:
Thomas Goyne 2012-10-02 12:28:55 -07:00
parent 0346fbf715
commit 40f97dbfea
6 changed files with 58 additions and 168 deletions

View File

@ -36,6 +36,8 @@
#include "config.h" #include "config.h"
#include "aegisublocale.h"
#ifndef AGI_PRE #ifndef AGI_PRE
#include <algorithm> #include <algorithm>
#include <functional> #include <functional>
@ -48,97 +50,59 @@
#include <wx/choicdlg.h> // Keep this last so wxUSE_CHOICEDLG is set. #include <wx/choicdlg.h> // Keep this last so wxUSE_CHOICEDLG is set.
#endif #endif
#include "aegisublocale.h"
#include "standard_paths.h" #include "standard_paths.h"
AegisubLocale::~AegisubLocale() { #ifndef AEGISUB_CATALOG
} #define AEGISUB_CATALOG "aegisub"
int AegisubLocale::EnglishId() const {
static const int english_ids[] = {
wxLANGUAGE_ENGLISH,
wxLANGUAGE_ENGLISH_US,
wxLANGUAGE_ENGLISH_UK,
wxLANGUAGE_ENGLISH_AUSTRALIA,
wxLANGUAGE_ENGLISH_BELIZE,
wxLANGUAGE_ENGLISH_BOTSWANA,
wxLANGUAGE_ENGLISH_CANADA,
wxLANGUAGE_ENGLISH_CARIBBEAN,
wxLANGUAGE_ENGLISH_DENMARK,
wxLANGUAGE_ENGLISH_EIRE,
wxLANGUAGE_ENGLISH_JAMAICA,
wxLANGUAGE_ENGLISH_NEW_ZEALAND,
wxLANGUAGE_ENGLISH_PHILIPPINES,
wxLANGUAGE_ENGLISH_SOUTH_AFRICA,
wxLANGUAGE_ENGLISH_TRINIDAD,
wxLANGUAGE_ENGLISH_ZIMBABWE,
0
};
for (const int *id = english_ids; *id; ++id) {
if (wxLocale::IsAvailable(*id)) {
return *id;
}
}
return -1;
}
void AegisubLocale::Init(int language) {
if (language == -1)
language = EnglishId();
if (!wxLocale::IsAvailable(language))
language = wxLANGUAGE_UNKNOWN;
locale.reset(new wxLocale(language));
#ifdef __WINDOWS__
locale->AddCatalogLookupPathPrefix(StandardPaths::DecodePath("?data/locale/"));
locale->AddCatalog("aegisub");
#else
locale->AddCatalog(AEGISUB_CATALOG);
#endif #endif
locale->AddCatalog("wxstd"); AegisubLocale::AegisubLocale() {
setlocale(LC_NUMERIC, "C"); wxTranslations::Set(new wxTranslations);
setlocale(LC_CTYPE, "C"); wxFileTranslationsLoader::AddCatalogLookupPathPrefix(StandardPaths::DecodePath("?data/locale/"));
} }
int AegisubLocale::PickLanguage() { void AegisubLocale::Init(wxString const& language) {
wxArrayInt langs = GetAvailableLanguages(); wxTranslations *translations = wxTranslations::Get();
translations->SetLanguage(language);
translations->AddCatalog(AEGISUB_CATALOG);
translations->AddStdCatalog();
// Check if english is in it, else add it setlocale(LC_NUMERIC, "C");
if (langs.Index(wxLANGUAGE_ENGLISH) == wxNOT_FOUND) { setlocale(LC_CTYPE, "C");
int id = EnglishId(); active_language = language;
if (id) }
langs.Insert(id, 0);
} wxString AegisubLocale::PickLanguage() {
wxArrayString langs = wxTranslations::Get()->GetAvailableTranslations(AEGISUB_CATALOG);
langs.insert(langs.begin(), "en_US");
// Check if user local language is available, if so, make it first // Check if user local language is available, if so, make it first
int user = wxLocale::GetSystemLanguage(); const wxLanguageInfo *info = wxLocale::GetLanguageInfo(wxLocale::GetSystemLanguage());
if (langs.Index(user) != wxNOT_FOUND) { if (info) {
langs.Remove(user); wxArrayString::iterator it = std::find(langs.begin(), langs.end(), info->CanonicalName);
langs.Insert(user, 0); if (it != langs.end())
std::rotate(langs.begin(), it, it + 1);
} }
// Remove languages which won't work due to the locale not being installed
langs.erase(remove_if(langs.begin(), langs.end(), not1(std::ptr_fun(&wxLocale::IsAvailable))), langs.end());
// Nothing to pick // Nothing to pick
if (langs.empty()) return -1; if (langs.empty()) return "";
// Only one language, so don't bother asking the user // Only one language, so don't bother asking the user
if (langs.size() == 1 && !locale) if (langs.size() == 1 && !active_language)
return langs[0]; return langs[0];
// Generate names // Generate names
wxArrayString langNames; wxArrayString langNames;
for (size_t i = 0; i < langs.size(); ++i) for (size_t i = 0; i < langs.size(); ++i) {
langNames.Add(wxLocale::GetLanguageName(langs[i])); const wxLanguageInfo *info = wxLocale::FindLanguageInfo(langs[i]);
if (info)
langNames.push_back(wxLocale::GetLanguageName(info->Language));
else
langNames.push_back(langs[i]);
}
long style = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxOK | wxCENTRE; long style = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxOK | wxCENTRE;
if (locale) if (!active_language.empty())
style |= wxCANCEL; style |= wxCANCEL;
wxSingleChoiceDialog dialog(NULL, "Please choose a language:", "Language", langNames, wxSingleChoiceDialog dialog(NULL, "Please choose a language:", "Language", langNames,
@ -150,75 +114,9 @@ int AegisubLocale::PickLanguage() {
style); style);
if (dialog.ShowModal() == wxID_OK) { if (dialog.ShowModal() == wxID_OK) {
int picked = dialog.GetSelection(); int picked = dialog.GetSelection();
if (locale && langs[picked] == locale->GetLanguage()) if (langs[picked] != active_language)
return -1; return langs[picked];
return langs[picked];
} }
return -1; return "";
}
wxArrayInt AegisubLocale::GetAvailableLanguages() {
wxArrayInt final;
#ifdef __WINDOWS__
// Open directory
wxString folder = StandardPaths::DecodePath("?data/locale/");
wxDir dir;
if (!dir.Exists(folder)) return final;
if (!dir.Open(folder)) return final;
// Enumerate folders
wxString temp1;
for (bool cont = dir.GetFirst(&temp1, "", wxDIR_DIRS); cont; cont = dir.GetNext(&temp1)) {
// Check if .so exists inside folder
if (wxFileName::FileExists(folder + temp1 + "/aegisub.mo")) {
const wxLanguageInfo *lang = wxLocale::FindLanguageInfo(temp1);
if (lang) {
final.Add(lang->Language);
}
}
}
#else
const char* langs[] = {
"ca",
"cs",
"da",
"de",
"el",
"es",
"eu",
"fa",
"fi",
"fr_FR",
"hu",
"id",
"it",
"ja",
"ko",
"pl",
"pt_BR",
"pt_PT",
"ru",
"sr_RS",
"sr_RS@latin",
"sr_YU",
"sr_YU@latin",
"vi",
"zh_CN",
"zh_TW"
};
size_t len = sizeof(langs)/sizeof(char*);
for (size_t i=0; i<len; i++) {
const wxLanguageInfo *lang = wxLocale::FindLanguageInfo(langs[i]);
// If the locale file doesn't exist then don't list it as an option.
wxString locDir = wxStandardPaths::Get().GetLocalizedResourcesDir(langs[i], wxStandardPathsBase::ResourceCat_Messages);
wxFileName file(wxString::Format("%s/%s.mo", locDir, AEGISUB_CATALOG));
if (lang && file.FileExists()) final.Add(lang->Language);
}
#endif
return final;
} }

View File

@ -34,22 +34,15 @@
/// @ingroup utility /// @ingroup utility
/// ///
#include <libaegisub/scoped_ptr.h>
class wxLocale;
/// DOCME /// DOCME
/// @class AegisubLocale /// @class AegisubLocale
/// @brief DOCME /// @brief DOCME
/// ///
/// DOCME /// DOCME
class AegisubLocale { class AegisubLocale {
agi::scoped_ptr<wxLocale> locale; wxString active_language;
wxArrayInt GetAvailableLanguages();
int EnglishId() const;
public: public:
~AegisubLocale(); AegisubLocale();
void Init(int language); void Init(wxString const& language);
int PickLanguage(); wxString PickLanguage();
}; };

View File

@ -50,6 +50,7 @@
#include "../main.h" #include "../main.h"
#include "../audio_controller.h" #include "../audio_controller.h"
#include "../compat.h"
#include "../dialog_about.h" #include "../dialog_about.h"
#include "../dialog_detached_video.h" #include "../dialog_detached_video.h"
#include "../dialog_manager.h" #include "../dialog_manager.h"
@ -185,19 +186,17 @@ struct app_language : public Command {
void operator()(agi::Context *c) { void operator()(agi::Context *c) {
// Get language // Get language
int newCode = wxGetApp().locale.PickLanguage(); wxString new_language = wxGetApp().locale.PickLanguage();
// Is OK? if (!new_language) return;
if (newCode != -1) {
// Set code
OPT_SET("App/Locale")->SetInt(newCode);
// Ask to restart program OPT_SET("App/Language")->SetString(STD_STR(new_language));
int result = wxMessageBox("Aegisub needs to be restarted so that the new language can be applied. Restart now?", "Restart Aegisub?", wxYES_NO | wxICON_QUESTION | wxCENTER);
if (result == wxYES) { // Ask to restart program
// Restart Aegisub int result = wxMessageBox("Aegisub needs to be restarted so that the new language can be applied. Restart now?", "Restart Aegisub?", wxYES_NO | wxICON_QUESTION | wxCENTER);
if (wxGetApp().frame->Close()) { if (result == wxYES) {
RestartAegisub(); // Restart Aegisub
} if (wxGetApp().frame->Close()) {
RestartAegisub();
} }
} }
} }

View File

@ -10,7 +10,7 @@
}, },
"Call Tips" : false, "Call Tips" : false,
"First Start" : true, "First Start" : true,
"Locale" : -1, "Language" : "",
"Maximized" : false, "Maximized" : false,
"Save Charset" : "UTF-8", "Save Charset" : "UTF-8",
"Show Toolbar" : true, "Show Toolbar" : true,

View File

@ -10,7 +10,7 @@
}, },
"Call Tips" : false, "Call Tips" : false,
"First Start" : true, "First Start" : true,
"Locale" : -1, "Language" : "",
"Maximized" : false, "Maximized" : false,
"Save Charset" : "UTF-8", "Save Charset" : "UTF-8",
"Show Toolbar" : true, "Show Toolbar" : true,

View File

@ -233,10 +233,10 @@ bool AegisubApp::OnInit() {
StartupLog("Initialize final locale"); StartupLog("Initialize final locale");
// Set locale // Set locale
int lang = OPT_GET("App/Locale")->GetInt(); wxString lang = lagi_wxString(OPT_GET("App/Language")->GetString());
if (lang == -1) { if (!lang) {
lang = locale.PickLanguage(); lang = locale.PickLanguage();
OPT_SET("App/Locale")->SetInt(lang); OPT_SET("App/Language")->SetString(STD_STR(lang));
} }
locale.Init(lang); locale.Init(lang);