From a4940bf6968392df5727b6176d83f6b195828c2e Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 3 Aug 2021 01:14:24 +0200 Subject: [PATCH 01/28] Extract wxLocaleSetter from the tests into a private header This will allow using this class in the library code too. No real changes yet, this is a pure refactoring. This commit is best viewed using git --color-moved option. --- include/wx/private/localeset.h | 49 +++++++++++++++++++++++++++++++++ tests/controls/textctrltest.cpp | 4 ++- tests/datetime/datetimetest.cpp | 4 ++- tests/filename/filenametest.cpp | 4 ++- tests/mbconv/mbconvtest.cpp | 4 ++- tests/strings/vsnprintf.cpp | 5 ++-- tests/testprec.h | 32 --------------------- 7 files changed, 64 insertions(+), 38 deletions(-) create mode 100644 include/wx/private/localeset.h diff --git a/include/wx/private/localeset.h b/include/wx/private/localeset.h new file mode 100644 index 0000000000..a977247d6b --- /dev/null +++ b/include/wx/private/localeset.h @@ -0,0 +1,49 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/private/localeset.h +// Purpose: Define helper wxLocaleSetter class. +// Author: Vadim Zeitlin +// Created: 2021-08-03 (extracted from tests/testprec.h) +// Copyright: (c) 2021 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_PRIVATE_LOCALESET_H_ +#define _WX_PRIVATE_LOCALESET_H_ + +#include "wx/crt.h" // wxStrdupA() + +#include + +// Helper class setting the locale to the given one for its lifetime. +class wxLocaleSetter +{ +public: + wxLocaleSetter(const char *loc) + : m_locOld(wxStrdupA(setlocale(LC_ALL, NULL))) + { + setlocale(LC_ALL, loc); + } + + ~wxLocaleSetter() + { + setlocale(LC_ALL, m_locOld); + free(m_locOld); + } + +private: + char * const m_locOld; + + wxDECLARE_NO_COPY_CLASS(wxLocaleSetter); +}; + +// An even simpler helper for setting the locale to "C" one during its lifetime. +class wxCLocaleSetter : private wxLocaleSetter +{ +public: + wxCLocaleSetter() : wxLocaleSetter("C") { } + +private: + wxDECLARE_NO_COPY_CLASS(wxCLocaleSetter); +}; + +#endif // _WX_PRIVATE_LOCALESET_H_ diff --git a/tests/controls/textctrltest.cpp b/tests/controls/textctrltest.cpp index 9d17f13892..2b79361abf 100644 --- a/tests/controls/textctrltest.cpp +++ b/tests/controls/textctrltest.cpp @@ -32,6 +32,8 @@ #include "wx/stopwatch.h" #endif +#include "wx/private/localeset.h" + #include "textentrytest.h" #include "testableframe.h" #include "asserthelper.h" @@ -288,7 +290,7 @@ void TextCtrlTestCase::StreamInput() #ifndef __WXOSX__ { // Ensure we use decimal point and not a comma. - LocaleSetter setCLocale("C"); + wxCLocaleSetter setCLocale; *m_text << "stringinput" << 10 diff --git a/tests/datetime/datetimetest.cpp b/tests/datetime/datetimetest.cpp index 8ecf70f2c6..0a03babc54 100644 --- a/tests/datetime/datetimetest.cpp +++ b/tests/datetime/datetimetest.cpp @@ -22,6 +22,8 @@ #include "wx/wxcrt.h" // for wxStrstr() +#include "wx/private/localeset.h" + // to test Today() meaningfully we must be able to change the system date which // is not usually the case, but if we're under Win32 we can try it -- define // the macro below to do it @@ -1304,7 +1306,7 @@ void DateTimeTestCase::TestDateTimeParse() // the test strings here use "PM" which is not available in all locales so // we need to use "C" locale for them - CLocaleSetter cloc; + wxCLocaleSetter cloc; wxDateTime dt; for ( size_t n = 0; n < WXSIZEOF(parseTestDates); n++ ) diff --git a/tests/filename/filenametest.cpp b/tests/filename/filenametest.cpp index a650deff7e..3134bbe53d 100644 --- a/tests/filename/filenametest.cpp +++ b/tests/filename/filenametest.cpp @@ -22,6 +22,8 @@ #include "wx/stdpaths.h" #include "wx/scopeguard.h" +#include "wx/private/localeset.h" + #ifdef __WINDOWS__ #include "wx/msw/registry.h" #include "wx/msw/wrapshl.h" @@ -493,7 +495,7 @@ TEST_CASE("wxFileName::GetHumanReadable", "[filename]") { "304 KB", 304351, 0, wxSIZE_CONV_SI }, }; - CLocaleSetter loc; // we want to use "C" locale for LC_NUMERIC + wxCLocaleSetter loc; // we want to use "C" locale for LC_NUMERIC // so that regardless of the system's locale // the decimal point used by GetHumanReadableSize() // is always '.' diff --git a/tests/mbconv/mbconvtest.cpp b/tests/mbconv/mbconvtest.cpp index 8306759fb0..53309c4b60 100644 --- a/tests/mbconv/mbconvtest.cpp +++ b/tests/mbconv/mbconvtest.cpp @@ -22,6 +22,8 @@ #include "wx/txtstrm.h" #include "wx/mstream.h" +#include "wx/private/localeset.h" + #if defined wxHAVE_TCHAR_SUPPORT && !defined HAVE_WCHAR_H #define HAVE_WCHAR_H #endif @@ -1106,7 +1108,7 @@ void MBConvTestCase::LibcTests() // supposed to use the same CRT -- no idea why and unfortunately gdb is too // flaky to debug it) #ifdef __VISUALC__ - LocaleSetter loc("English_United States.1252"); + wxLocaleSetter loc("English_United States.1252"); wxMBConvLibc convLibc; TestCoder( diff --git a/tests/strings/vsnprintf.cpp b/tests/strings/vsnprintf.cpp index 53f48c3e2e..f1fa10f99f 100644 --- a/tests/strings/vsnprintf.cpp +++ b/tests/strings/vsnprintf.cpp @@ -24,6 +24,7 @@ #include "wx/wxchar.h" #endif // WX_PRECOMP +#include "wx/private/localeset.h" // NOTE: for more info about the specification of wxVsnprintf() behaviour you can // refer to the following page of the GNU libc manual: @@ -85,10 +86,10 @@ wxUnsafeSnprintf(T *buf, size_t len, const wxChar *fmt, ...) // Explicitly set C locale to avoid check failures when running on machines // with a locale where the decimal point is not '.' -class VsnprintfTestCase : CLocaleSetter +class VsnprintfTestCase : wxCLocaleSetter { public: - VsnprintfTestCase() : CLocaleSetter() { } + VsnprintfTestCase() : wxCLocaleSetter() { } protected: template diff --git a/tests/testprec.h b/tests/testprec.h index d3340eff03..c51fa34792 100644 --- a/tests/testprec.h +++ b/tests/testprec.h @@ -147,38 +147,6 @@ extern bool IsAutomaticTest(); extern bool IsRunningUnderXVFB(); -// Helper class setting the locale to the given one for its lifetime. -class LocaleSetter -{ -public: - LocaleSetter(const char *loc) - : m_locOld(wxStrdupA(setlocale(LC_ALL, NULL))) - { - setlocale(LC_ALL, loc); - } - - ~LocaleSetter() - { - setlocale(LC_ALL, m_locOld); - free(m_locOld); - } - -private: - char * const m_locOld; - - wxDECLARE_NO_COPY_CLASS(LocaleSetter); -}; - -// An even simpler helper for setting the locale to "C" one during its lifetime. -class CLocaleSetter : private LocaleSetter -{ -public: - CLocaleSetter() : LocaleSetter("C") { } - -private: - wxDECLARE_NO_COPY_CLASS(CLocaleSetter); -}; - #if wxUSE_GUI // Return true if the UI tests are enabled, used by WXUISIM_TEST(). From 33ae58e4576ed936f7d3ea7a5640762befa60596 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 3 Aug 2021 01:41:27 +0200 Subject: [PATCH 02/28] Allow using wxLOCALE_CAT_DEFAULT for numeric or money locale info Make GetInfo() return information for numbers by default in the Unix version too instead of asserting, as this is more consistent with the MSW and Mac versions and also seems more useful. --- interface/wx/intl.h | 6 ++++++ src/common/intl.cpp | 32 ++++++++++++++++++++++---------- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/interface/wx/intl.h b/interface/wx/intl.h index 92902c1b7d..7cd5ab6964 100644 --- a/interface/wx/intl.h +++ b/interface/wx/intl.h @@ -116,6 +116,9 @@ enum wxLocaleInfo This value can be used with either wxLOCALE_CAT_NUMBER or wxLOCALE_CAT_MONEY categories. + + By default, i.e. when wxLOCALE_CAT_DEFAULT is used, the separator for + numbers is returned. */ wxLOCALE_THOUSANDS_SEP, @@ -124,6 +127,9 @@ enum wxLocaleInfo This value can be used with either wxLOCALE_CAT_NUMBER or wxLOCALE_CAT_MONEY categories. + + By default, i.e. when wxLOCALE_CAT_DEFAULT is used, the decimal point + for numbers is returned. */ wxLOCALE_DECIMAL_POINT, diff --git a/src/common/intl.cpp b/src/common/intl.cpp index 6dc41e4b05..d9b166557d 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -1935,22 +1935,34 @@ wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory cat) switch ( index ) { case wxLOCALE_THOUSANDS_SEP: - if ( cat == wxLOCALE_CAT_NUMBER ) - return lc->thousands_sep; - else if ( cat == wxLOCALE_CAT_MONEY ) - return lc->mon_thousands_sep; + switch ( cat ) + { + case wxLOCALE_CAT_DEFAULT: + case wxLOCALE_CAT_NUMBER: + return lc->thousands_sep; - wxFAIL_MSG( "invalid wxLocaleCategory" ); + case wxLOCALE_CAT_MONEY: + return lc->mon_thousands_sep; + + default: + wxFAIL_MSG( "invalid wxLocaleCategory" ); + } break; case wxLOCALE_DECIMAL_POINT: - if ( cat == wxLOCALE_CAT_NUMBER ) - return lc->decimal_point; - else if ( cat == wxLOCALE_CAT_MONEY ) - return lc->mon_decimal_point; + switch ( cat ) + { + case wxLOCALE_CAT_DEFAULT: + case wxLOCALE_CAT_NUMBER: + return lc->decimal_point; - wxFAIL_MSG( "invalid wxLocaleCategory" ); + case wxLOCALE_CAT_MONEY: + return lc->mon_decimal_point; + + default: + wxFAIL_MSG( "invalid wxLocaleCategory" ); + } break; case wxLOCALE_SHORT_DATE_FMT: From 93190d6263ec392bc0be2d978a75eab437e5754b Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Fri, 6 Aug 2021 00:19:03 +0200 Subject: [PATCH 03/28] Interpret empty language as "default" in the internat sample This provides a more convenient way of testing wxLANGUAGE_DEFAULT than selecting it from the dialog shown on startup. This commit is best viewed ignoring whitespace-only changes. --- samples/internat/internat.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/samples/internat/internat.cpp b/samples/internat/internat.cpp index 5502619b53..478d91d391 100644 --- a/samples/internat/internat.cpp +++ b/samples/internat/internat.cpp @@ -215,14 +215,21 @@ bool MyApp::OnCmdLineParsed(wxCmdLineParser& parser) if ( parser.GetParamCount() ) { const wxString loc = parser.GetParam(); - const wxLanguageInfo * const lang = wxLocale::FindLanguageInfo(loc); - if ( !lang ) + if ( loc.empty() ) { - wxLogError(_("Locale \"%s\" is unknown."), loc); - return false; + m_lang = wxLANGUAGE_DEFAULT; } + else + { + const wxLanguageInfo * const lang = wxLocale::FindLanguageInfo(loc); + if ( !lang ) + { + wxLogError(_("Locale \"%s\" is unknown."), loc); + return false; + } - m_lang = static_cast(lang->Language); + m_lang = static_cast(lang->Language); + } } return true; From 1f74e7cd1bd5de003768160c96671781ba06cc10 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Wed, 4 Aug 2021 22:54:16 +0200 Subject: [PATCH 04/28] Show more locale-dependent controls in the internat sample Show that file dialogs, spin and calendar controls also respect the selected locale conventions. --- samples/internat/internat.cpp | 38 +++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/samples/internat/internat.cpp b/samples/internat/internat.cpp index 478d91d391..9437d702db 100644 --- a/samples/internat/internat.cpp +++ b/samples/internat/internat.cpp @@ -28,11 +28,13 @@ #include "wx/wx.h" #endif +#include "wx/calctrl.h" #include "wx/intl.h" #include "wx/file.h" #include "wx/log.h" #include "wx/cmdline.h" #include "wx/platinfo.h" +#include "wx/spinctrl.h" #ifndef wxHAS_IMAGES_IN_RESOURCES #include "../sample.xpm" @@ -80,6 +82,7 @@ public: void OnPlay(wxCommandEvent& event); void OnOpen(wxCommandEvent& event); + void OnSave(wxCommandEvent& event); void OnTest1(wxCommandEvent& event); void OnTest2(wxCommandEvent& event); void OnTest3(wxCommandEvent& event); @@ -181,6 +184,7 @@ wxBEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_MENU(INTERNAT_PLAY, MyFrame::OnPlay) EVT_MENU(wxID_OPEN, MyFrame::OnOpen) + EVT_MENU(wxID_SAVE, MyFrame::OnSave) EVT_MENU(INTERNAT_TEST_1, MyFrame::OnTest1) EVT_MENU(INTERNAT_TEST_2, MyFrame::OnTest2) EVT_MENU(INTERNAT_TEST_3, MyFrame::OnTest3) @@ -323,6 +327,7 @@ MyFrame::MyFrame(wxLocale& locale) wxMenu *test_menu = new wxMenu; test_menu->Append(wxID_OPEN, _("&Open bogus file"), _("Shows a wxWidgets localized error message")); + test_menu->Append(wxID_SAVE, _("&Save dummy file"), _("Shows a localized standard dialog")); test_menu->Append(INTERNAT_PLAY, _("&Play a game"), _("A little game; hint: 17 is a lucky number for many")); test_menu->AppendSeparator(); test_menu->Append(INTERNAT_TEST_1, _("&1 _() (gettext)"), _("Tests the _() macro")); @@ -367,13 +372,27 @@ MyFrame::MyFrame(wxLocale& locale) // this demonstrates RTL support in wxStatusBar: CreateStatusBar(1); - // this demonstrates RTL layout mirroring for Arabic locales + // create some controls affected by the locale + wxSizer* const topSizer = new wxBoxSizer(wxVERTICAL); + + // this demonstrates RTL layout mirroring for Arabic locales and using + // locale-specific decimal separator in wxSpinCtrlDouble. wxSizer *sizer = new wxBoxSizer(wxHORIZONTAL); - sizer->Add(new wxStaticText(this, wxID_ANY, _("First")), - wxSizerFlags().Border()); - sizer->Add(new wxStaticText(this, wxID_ANY, _("Second")), - wxSizerFlags().Border()); - SetSizer(sizer); + sizer->Add(new wxStaticText(this, wxID_ANY, _("Numeric input:")), + wxSizerFlags().Center().Border()); + + wxSpinCtrlDouble* const spin = new wxSpinCtrlDouble(this, wxID_ANY); + spin->SetDigits(2); + spin->SetValue(12.34); + sizer->Add(spin, wxSizerFlags().Center().Border()); + + topSizer->Add(sizer, wxSizerFlags().Center()); + + // show that week days and months names are translated too + topSizer->Add(new wxCalendarCtrl(this, wxID_ANY), + wxSizerFlags().Center().Border()); + + SetSizer(topSizer); } void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event) ) @@ -517,6 +536,13 @@ void MyFrame::OnOpen(wxCommandEvent& WXUNUSED(event)) wxFile file("NOTEXIST.ING"); } +void MyFrame::OnSave(wxCommandEvent& WXUNUSED(event)) +{ + // show this file dialog just to check that the locale-specific elements in + // it (such as dates) follow the current locale convnetions + wxSaveFileSelector(_("Dummy file dialog"), ".ext", "dummy", this); +} + void MyFrame::OnTest1(wxCommandEvent& WXUNUSED(event)) { const wxString& title = _("Testing _() (gettext)"); From 7dc646256189e16c55fdb3d6dacbb62a34c3911f Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Fri, 6 Aug 2021 00:47:15 +0200 Subject: [PATCH 05/28] Show using wxNumberFormatter in the internat sample too This shows that C and UI (or OS) locales can be different. --- samples/internat/internat.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/samples/internat/internat.cpp b/samples/internat/internat.cpp index 9437d702db..b243bc3ab0 100644 --- a/samples/internat/internat.cpp +++ b/samples/internat/internat.cpp @@ -33,6 +33,7 @@ #include "wx/file.h" #include "wx/log.h" #include "wx/cmdline.h" +#include "wx/numformatter.h" #include "wx/platinfo.h" #include "wx/spinctrl.h" @@ -392,7 +393,23 @@ MyFrame::MyFrame(wxLocale& locale) topSizer->Add(new wxCalendarCtrl(this, wxID_ANY), wxSizerFlags().Center().Border()); - SetSizer(topSizer); + // show the difference between wxString::Format() and wxNumberFormatter: + // the former uses the current C locale, while the latter uses the UI + // locale + topSizer->Add(new wxStaticText + ( + this, + wxID_ANY, + wxString::Format + ( + _("Number in UI locale: %s; in C locale: %.2f"), + wxNumberFormatter::ToString(5.67, 2), + 5.67 + ) + ), + wxSizerFlags().Center().Border()); + + SetSizerAndFit(topSizer); } void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event) ) From 4db5de9cdb8deec4931de72c93e43a4a730d26f9 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Fri, 6 Aug 2021 00:47:59 +0200 Subject: [PATCH 06/28] Use wxTranslations directly instead of passing by wxLocale This is slightly more verbose, but more clear and allows to separate the translations-related part from locale-changing one. --- samples/internat/internat.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/samples/internat/internat.cpp b/samples/internat/internat.cpp index b243bc3ab0..e9700dd89c 100644 --- a/samples/internat/internat.cpp +++ b/samples/internat/internat.cpp @@ -36,6 +36,7 @@ #include "wx/numformatter.h" #include "wx/platinfo.h" #include "wx/spinctrl.h" +#include "wx/translation.h" #ifndef wxHAS_IMAGES_IN_RESOURCES #include "../sample.xpm" @@ -271,11 +272,15 @@ bool MyApp::OnInit() // in the default locations, but when the program is not installed the // catalogs are in the build directory where we wouldn't find them by // default - wxLocale::AddCatalogLookupPathPrefix("."); + wxFileTranslationsLoader::AddCatalogLookupPathPrefix("."); + + // Create the object for message translation and set it up for global use. + wxTranslations* const trans = new wxTranslations(); + wxTranslations::Set(trans); // Initialize the catalogs we'll be using const wxLanguageInfo* pInfo = wxLocale::GetLanguageInfo(m_lang); - if (!m_locale.AddCatalog("internat")) + if ( !trans->AddCatalog("internat") ) { wxLogError(_("Couldn't find/load the 'internat' catalog for locale '%s'."), pInfo ? pInfo->GetLocaleName() : _("unknown")); @@ -283,7 +288,7 @@ bool MyApp::OnInit() // Now try to add wxstd.mo so that loading "NOTEXIST.ING" file will produce // a localized error message: - m_locale.AddCatalog("wxstd"); + trans->AddCatalog("wxstd"); // NOTE: it's not an error if we couldn't find it! // this catalog is installed in standard location on Linux systems and @@ -291,8 +296,8 @@ bool MyApp::OnInit() // // if it's not installed on your system, it is just silently ignored #ifdef USE_COREUTILS_MO - wxLocale::AddCatalogLookupPathPrefix("/usr/share/locale"); - g_loadedCoreutilsMO = m_locale.AddCatalog("coreutils"); + wxFileTranslationsLoader::AddCatalogLookupPathPrefix("/usr/share/locale"); + g_loadedCoreutilsMO = trans->AddCatalog("coreutils"); #endif // USE_COREUTILS_MO // Create the main frame window From e0cd2c637d9db99dea277af5f5f89e4fc2c419c3 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 7 Aug 2021 17:35:34 +0100 Subject: [PATCH 07/28] Use a panel in internat sample to make it look better under MSW Creating the controls directly on wxFrame is not recommended and looks ugly under MSW due to the wrong background being used, so add an intermediate panel. --- samples/internat/internat.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/samples/internat/internat.cpp b/samples/internat/internat.cpp index e9700dd89c..7e00f1dbc5 100644 --- a/samples/internat/internat.cpp +++ b/samples/internat/internat.cpp @@ -378,16 +378,18 @@ MyFrame::MyFrame(wxLocale& locale) // this demonstrates RTL support in wxStatusBar: CreateStatusBar(1); + wxPanel* const panel = new wxPanel(this); + // create some controls affected by the locale wxSizer* const topSizer = new wxBoxSizer(wxVERTICAL); // this demonstrates RTL layout mirroring for Arabic locales and using // locale-specific decimal separator in wxSpinCtrlDouble. wxSizer *sizer = new wxBoxSizer(wxHORIZONTAL); - sizer->Add(new wxStaticText(this, wxID_ANY, _("Numeric input:")), + sizer->Add(new wxStaticText(panel, wxID_ANY, _("Numeric input:")), wxSizerFlags().Center().Border()); - wxSpinCtrlDouble* const spin = new wxSpinCtrlDouble(this, wxID_ANY); + wxSpinCtrlDouble* const spin = new wxSpinCtrlDouble(panel, wxID_ANY); spin->SetDigits(2); spin->SetValue(12.34); sizer->Add(spin, wxSizerFlags().Center().Border()); @@ -395,7 +397,7 @@ MyFrame::MyFrame(wxLocale& locale) topSizer->Add(sizer, wxSizerFlags().Center()); // show that week days and months names are translated too - topSizer->Add(new wxCalendarCtrl(this, wxID_ANY), + topSizer->Add(new wxCalendarCtrl(panel, wxID_ANY), wxSizerFlags().Center().Border()); // show the difference between wxString::Format() and wxNumberFormatter: @@ -403,7 +405,7 @@ MyFrame::MyFrame(wxLocale& locale) // locale topSizer->Add(new wxStaticText ( - this, + panel, wxID_ANY, wxString::Format ( @@ -414,7 +416,8 @@ MyFrame::MyFrame(wxLocale& locale) ), wxSizerFlags().Center().Border()); - SetSizerAndFit(topSizer); + panel->SetSizer(topSizer); + topSizer->SetSizeHints(this); } void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event) ) From 4adb58b7ea55b60355f18fd7bdcfa2b64cf4eab3 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 7 Aug 2021 18:27:13 +0200 Subject: [PATCH 08/28] Add an option to skip changing locale in the internat sample Show that we can use the translations to the user language even without changing the locale. --- samples/internat/internat.cpp | 58 ++++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/samples/internat/internat.cpp b/samples/internat/internat.cpp index 7e00f1dbc5..57aa0949a2 100644 --- a/samples/internat/internat.cpp +++ b/samples/internat/internat.cpp @@ -57,7 +57,7 @@ class MyApp: public wxApp { public: - MyApp() { m_lang = wxLANGUAGE_UNKNOWN; } + MyApp() { m_lang = wxLANGUAGE_UNKNOWN; m_setLocale = true; } virtual void OnInitCmdLine(wxCmdLineParser& parser) wxOVERRIDE; virtual bool OnCmdLineParsed(wxCmdLineParser& parser) wxOVERRIDE; @@ -65,6 +65,7 @@ public: protected: wxLanguage m_lang; // language specified by user + bool m_setLocale; // if false, skip setting locale entirely wxLocale m_locale; // locale we'll be using }; @@ -204,8 +205,14 @@ wxIMPLEMENT_APP(MyApp); // ---------------------------------------------------------------------------- // command line arguments handling + +static const char* OPTION_NO_LOCALE = "no-locale"; + void MyApp::OnInitCmdLine(wxCmdLineParser& parser) { + parser.AddSwitch("n", OPTION_NO_LOCALE, + _("skip setting locale on startup")); + parser.AddParam(_("locale"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); @@ -218,8 +225,20 @@ bool MyApp::OnCmdLineParsed(wxCmdLineParser& parser) if ( !wxApp::OnCmdLineParsed(parser) ) return false; + if ( parser.Found(OPTION_NO_LOCALE) ) + { + m_setLocale = false; + } + if ( parser.GetParamCount() ) { + if ( !m_setLocale ) + { + wxLogError("Locale parameter ignored when %s option is used.", + OPTION_NO_LOCALE); + return false; + } + const wxString loc = parser.GetParam(); if ( loc.empty() ) { @@ -247,25 +266,34 @@ bool MyApp::OnInit() if ( !wxApp::OnInit() ) return false; - if ( m_lang == wxLANGUAGE_UNKNOWN ) + if ( m_setLocale ) { - int lng = wxGetSingleChoiceIndex - ( - _("Please choose language:"), - _("Language"), - WXSIZEOF(langNames), - langNames - ); - m_lang = lng == -1 ? wxLANGUAGE_DEFAULT : langIds[lng]; + if ( m_lang == wxLANGUAGE_UNKNOWN ) + { + int lng = wxGetSingleChoiceIndex + ( + "Please choose a language or cancel to skip changing it:", + "Language", + WXSIZEOF(langNames), + langNames + ); + if ( lng == -1 ) + m_setLocale = false; + else + m_lang = langIds[lng]; + } } - // don't use wxLOCALE_LOAD_DEFAULT flag so that Init() doesn't return - // false just because it failed to load wxstd catalog - if ( !m_locale.Init(m_lang, wxLOCALE_DONT_LOAD_DEFAULT) ) + if ( m_setLocale ) { - wxLogWarning(_("This language is not supported by the system.")); + // don't use wxLOCALE_LOAD_DEFAULT flag so that Init() doesn't return + // false just because it failed to load wxstd catalog + if ( !m_locale.Init(m_lang, wxLOCALE_DONT_LOAD_DEFAULT) ) + { + wxLogWarning(_("This language is not supported by the system.")); - // continue nevertheless + // continue nevertheless + } } // normally this wouldn't be necessary as the catalog files would be found From eb5bffd3caee3225f64bef56bb6b6e8147e81887 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 10 Aug 2021 17:12:01 +0200 Subject: [PATCH 09/28] Stop allowing to select the language in the internat sample Restrict the choice to using the current system locale or not using it, as setting any other language doesn't, and can't, work under macOS. --- samples/internat/internat.cpp | 143 +++++++--------------------------- 1 file changed, 30 insertions(+), 113 deletions(-) diff --git a/samples/internat/internat.cpp b/samples/internat/internat.cpp index 57aa0949a2..971273a05a 100644 --- a/samples/internat/internat.cpp +++ b/samples/internat/internat.cpp @@ -57,14 +57,13 @@ class MyApp: public wxApp { public: - MyApp() { m_lang = wxLANGUAGE_UNKNOWN; m_setLocale = true; } + MyApp() { m_setLocale = true; } virtual void OnInitCmdLine(wxCmdLineParser& parser) wxOVERRIDE; virtual bool OnCmdLineParsed(wxCmdLineParser& parser) wxOVERRIDE; virtual bool OnInit() wxOVERRIDE; protected: - wxLanguage m_lang; // language specified by user bool m_setLocale; // if false, skip setting locale entirely wxLocale m_locale; // locale we'll be using }; @@ -120,59 +119,6 @@ enum INTERNAT_MACRO_9 }; -// language data -static const wxLanguage langIds[] = -{ - wxLANGUAGE_DEFAULT, - wxLANGUAGE_FRENCH, - wxLANGUAGE_ITALIAN, - wxLANGUAGE_GERMAN, - wxLANGUAGE_RUSSIAN, - wxLANGUAGE_BULGARIAN, - wxLANGUAGE_CZECH, - wxLANGUAGE_POLISH, - wxLANGUAGE_SWEDISH, -#if wxUSE_UNICODE || defined(__WXMOTIF__) - wxLANGUAGE_JAPANESE, -#endif -#if wxUSE_UNICODE - wxLANGUAGE_GEORGIAN, - wxLANGUAGE_ENGLISH, - wxLANGUAGE_ENGLISH_US, - wxLANGUAGE_ARABIC, - wxLANGUAGE_ARABIC_EGYPT -#endif -}; - -// note that it makes no sense to translate these strings, they are -// shown before we set the locale anyhow -const wxString langNames[] = -{ - "System default", - "French", - "Italian", - "German", - "Russian", - "Bulgarian", - "Czech", - "Polish", - "Swedish", -#if wxUSE_UNICODE || defined(__WXMOTIF__) - "Japanese", -#endif -#if wxUSE_UNICODE - "Georgian", - "English", - "English (U.S.)", - "Arabic", - "Arabic (Egypt)" -#endif -}; - -// the arrays must be in sync -wxCOMPILE_TIME_ASSERT( WXSIZEOF(langNames) == WXSIZEOF(langIds), - LangArraysMismatch ); - // ---------------------------------------------------------------------------- // wxWidgets macros // ---------------------------------------------------------------------------- @@ -213,10 +159,6 @@ void MyApp::OnInitCmdLine(wxCmdLineParser& parser) parser.AddSwitch("n", OPTION_NO_LOCALE, _("skip setting locale on startup")); - parser.AddParam(_("locale"), - wxCMD_LINE_VAL_STRING, - wxCMD_LINE_PARAM_OPTIONAL); - wxApp::OnInitCmdLine(parser); } @@ -230,33 +172,6 @@ bool MyApp::OnCmdLineParsed(wxCmdLineParser& parser) m_setLocale = false; } - if ( parser.GetParamCount() ) - { - if ( !m_setLocale ) - { - wxLogError("Locale parameter ignored when %s option is used.", - OPTION_NO_LOCALE); - return false; - } - - const wxString loc = parser.GetParam(); - if ( loc.empty() ) - { - m_lang = wxLANGUAGE_DEFAULT; - } - else - { - const wxLanguageInfo * const lang = wxLocale::FindLanguageInfo(loc); - if ( !lang ) - { - wxLogError(_("Locale \"%s\" is unknown."), loc); - return false; - } - - m_lang = static_cast(lang->Language); - } - } - return true; } @@ -266,36 +181,39 @@ bool MyApp::OnInit() if ( !wxApp::OnInit() ) return false; - if ( m_setLocale ) - { - if ( m_lang == wxLANGUAGE_UNKNOWN ) - { - int lng = wxGetSingleChoiceIndex - ( - "Please choose a language or cancel to skip changing it:", - "Language", - WXSIZEOF(langNames), - langNames - ); - if ( lng == -1 ) - m_setLocale = false; - else - m_lang = langIds[lng]; - } - } - - if ( m_setLocale ) + // For demonstration purposes only, ask the user if they want to run the + // program using the current system language. In real programs, we would do + // it unconditionally for localized programs -- or never do it at all for + // the other ones. + const wxLanguageInfo* const + langInfo = wxLocale::GetLanguageInfo(wxLANGUAGE_DEFAULT); + const wxString + langDesc = langInfo ? langInfo->Description + : "the default system locale"; + if ( m_setLocale && + wxMessageBox + ( + wxString::Format + ( + "Would you like to use the program in %s?", + langDesc + ), + "wxWidgets i18n (internat) sample", + wxYES_NO + ) == wxYES ) { // don't use wxLOCALE_LOAD_DEFAULT flag so that Init() doesn't return // false just because it failed to load wxstd catalog - if ( !m_locale.Init(m_lang, wxLOCALE_DONT_LOAD_DEFAULT) ) + if ( !m_locale.Init(wxLANGUAGE_DEFAULT, wxLOCALE_DONT_LOAD_DEFAULT) ) { - wxLogWarning(_("This language is not supported by the system.")); - - // continue nevertheless + wxLogWarning("Failed to initialize the default system locale."); } } + + // Independently of whether we set the locale or not, we always load the + // translations (for the default system language) here. + // normally this wouldn't be necessary as the catalog files would be found // in the default locations, but when the program is not installed the // catalogs are in the build directory where we wouldn't find them by @@ -306,12 +224,11 @@ bool MyApp::OnInit() wxTranslations* const trans = new wxTranslations(); wxTranslations::Set(trans); - // Initialize the catalogs we'll be using - const wxLanguageInfo* pInfo = wxLocale::GetLanguageInfo(m_lang); + // Initialize the catalogs we'll be using. if ( !trans->AddCatalog("internat") ) { - wxLogError(_("Couldn't find/load the 'internat' catalog for locale '%s'."), - pInfo ? pInfo->GetLocaleName() : _("unknown")); + wxLogError(_("Couldn't find/load 'internat' catalog for %s."), + langDesc); } // Now try to add wxstd.mo so that loading "NOTEXIST.ING" file will produce From 31677e597d494fd76ed39e53bd39464c39725799 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 10 Aug 2021 17:20:12 +0200 Subject: [PATCH 10/28] Don't load translations when setting the locale is disabled too It makes more sense to skip loading the translations too, if the user decided not to use the current locale. This commit is best viewed ignoring whitespace-only changes. --- samples/internat/internat.cpp | 79 +++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 35 deletions(-) diff --git a/samples/internat/internat.cpp b/samples/internat/internat.cpp index 971273a05a..ec22fb2070 100644 --- a/samples/internat/internat.cpp +++ b/samples/internat/internat.cpp @@ -190,8 +190,9 @@ bool MyApp::OnInit() const wxString langDesc = langInfo ? langInfo->Description : "the default system locale"; - if ( m_setLocale && - wxMessageBox + if ( m_setLocale ) + { + if ( wxMessageBox ( wxString::Format ( @@ -201,49 +202,57 @@ bool MyApp::OnInit() "wxWidgets i18n (internat) sample", wxYES_NO ) == wxYES ) - { - // don't use wxLOCALE_LOAD_DEFAULT flag so that Init() doesn't return - // false just because it failed to load wxstd catalog - if ( !m_locale.Init(wxLANGUAGE_DEFAULT, wxLOCALE_DONT_LOAD_DEFAULT) ) { - wxLogWarning("Failed to initialize the default system locale."); + // don't use wxLOCALE_LOAD_DEFAULT flag so that Init() doesn't return + // false just because it failed to load wxstd catalog + if ( !m_locale.Init(wxLANGUAGE_DEFAULT, wxLOCALE_DONT_LOAD_DEFAULT) ) + { + wxLogWarning("Failed to initialize the default system locale."); + } + } + else + { + m_setLocale = false; } } - // Independently of whether we set the locale or not, we always load the - // translations (for the default system language) here. - - // normally this wouldn't be necessary as the catalog files would be found - // in the default locations, but when the program is not installed the - // catalogs are in the build directory where we wouldn't find them by - // default - wxFileTranslationsLoader::AddCatalogLookupPathPrefix("."); - - // Create the object for message translation and set it up for global use. - wxTranslations* const trans = new wxTranslations(); - wxTranslations::Set(trans); - - // Initialize the catalogs we'll be using. - if ( !trans->AddCatalog("internat") ) + // Independently of whether we succeeded to set the locale or not, try to + // load the translations (for the default system language) here. But don't + // do it if the user explicitly selected not to use the current locale. + if ( m_setLocale ) { - wxLogError(_("Couldn't find/load 'internat' catalog for %s."), - langDesc); - } + // normally this wouldn't be necessary as the catalog files would be found + // in the default locations, but when the program is not installed the + // catalogs are in the build directory where we wouldn't find them by + // default + wxFileTranslationsLoader::AddCatalogLookupPathPrefix("."); - // Now try to add wxstd.mo so that loading "NOTEXIST.ING" file will produce - // a localized error message: - trans->AddCatalog("wxstd"); - // NOTE: it's not an error if we couldn't find it! + // Create the object for message translation and set it up for global use. + wxTranslations* const trans = new wxTranslations(); + wxTranslations::Set(trans); - // this catalog is installed in standard location on Linux systems and - // shows that you may make use of the standard message catalogs as well - // - // if it's not installed on your system, it is just silently ignored + // Initialize the catalogs we'll be using. + if ( !trans->AddCatalog("internat") ) + { + wxLogError(_("Couldn't find/load 'internat' catalog for %s."), + langDesc); + } + + // Now try to add wxstd.mo so that loading "NOTEXIST.ING" file will produce + // a localized error message: + trans->AddCatalog("wxstd"); + // NOTE: it's not an error if we couldn't find it! + + // this catalog is installed in standard location on Linux systems and + // shows that you may make use of the standard message catalogs as well + // + // if it's not installed on your system, it is just silently ignored #ifdef USE_COREUTILS_MO - wxFileTranslationsLoader::AddCatalogLookupPathPrefix("/usr/share/locale"); - g_loadedCoreutilsMO = trans->AddCatalog("coreutils"); + wxFileTranslationsLoader::AddCatalogLookupPathPrefix("/usr/share/locale"); + g_loadedCoreutilsMO = trans->AddCatalog("coreutils"); #endif // USE_COREUTILS_MO + } // Create the main frame window MyFrame *frame = new MyFrame(m_locale); From afe04f7c4aa39e956820d56c7e312e9a978b8efc Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 10 Aug 2021 17:27:02 +0200 Subject: [PATCH 11/28] Add internat sample command line option to skip the locale dialog Getting this dialog all the time is annoying when testing, so add another command line option to set the locale unconditionally. This commit is best viewed ignoring whitespace-only changes. --- samples/internat/internat.cpp | 81 +++++++++++++++++++++-------------- 1 file changed, 50 insertions(+), 31 deletions(-) diff --git a/samples/internat/internat.cpp b/samples/internat/internat.cpp index ec22fb2070..82e80f9e98 100644 --- a/samples/internat/internat.cpp +++ b/samples/internat/internat.cpp @@ -57,14 +57,23 @@ class MyApp: public wxApp { public: - MyApp() { m_setLocale = true; } + MyApp() { m_setLocale = Locale_Ask; } virtual void OnInitCmdLine(wxCmdLineParser& parser) wxOVERRIDE; virtual bool OnCmdLineParsed(wxCmdLineParser& parser) wxOVERRIDE; virtual bool OnInit() wxOVERRIDE; protected: - bool m_setLocale; // if false, skip setting locale entirely + // Specifies whether we should use the current locale or not. By default we + // ask the user about it, but it's possible to override this using the + // command line options. + enum + { + Locale_Ask, + Locale_Set, + Locale_Skip + } m_setLocale; + wxLocale m_locale; // locale we'll be using }; @@ -153,11 +162,14 @@ wxIMPLEMENT_APP(MyApp); // command line arguments handling static const char* OPTION_NO_LOCALE = "no-locale"; +static const char* OPTION_SET_LOCALE = "set-locale"; void MyApp::OnInitCmdLine(wxCmdLineParser& parser) { parser.AddSwitch("n", OPTION_NO_LOCALE, _("skip setting locale on startup")); + parser.AddSwitch("y", OPTION_SET_LOCALE, + _("do set locale on startup without asking")); wxApp::OnInitCmdLine(parser); } @@ -169,7 +181,18 @@ bool MyApp::OnCmdLineParsed(wxCmdLineParser& parser) if ( parser.Found(OPTION_NO_LOCALE) ) { - m_setLocale = false; + m_setLocale = Locale_Skip; + } + + if ( parser.Found(OPTION_SET_LOCALE) ) + { + if ( m_setLocale == Locale_Skip ) + { + wxLogWarning("--%s option overrides --%s", + OPTION_SET_LOCALE, OPTION_NO_LOCALE); + } + + m_setLocale = Locale_Set; } return true; @@ -190,38 +213,34 @@ bool MyApp::OnInit() const wxString langDesc = langInfo ? langInfo->Description : "the default system locale"; - if ( m_setLocale ) + + if ( m_setLocale == Locale_Ask ) { - if ( wxMessageBox - ( - wxString::Format - ( - "Would you like to use the program in %s?", - langDesc - ), - "wxWidgets i18n (internat) sample", - wxYES_NO - ) == wxYES ) - { - // don't use wxLOCALE_LOAD_DEFAULT flag so that Init() doesn't return - // false just because it failed to load wxstd catalog - if ( !m_locale.Init(wxLANGUAGE_DEFAULT, wxLOCALE_DONT_LOAD_DEFAULT) ) - { - wxLogWarning("Failed to initialize the default system locale."); - } - } - else - { - m_setLocale = false; - } + m_setLocale = wxMessageBox + ( + wxString::Format + ( + "Would you like to use the program in %s?", + langDesc + ), + "wxWidgets i18n (internat) sample", + wxYES_NO + ) == wxYES ? Locale_Set : Locale_Skip; } - - // Independently of whether we succeeded to set the locale or not, try to - // load the translations (for the default system language) here. But don't - // do it if the user explicitly selected not to use the current locale. - if ( m_setLocale ) + if ( m_setLocale == Locale_Set ) { + // don't use wxLOCALE_LOAD_DEFAULT flag so that Init() doesn't return + // false just because it failed to load wxstd catalog + if ( !m_locale.Init(wxLANGUAGE_DEFAULT, wxLOCALE_DONT_LOAD_DEFAULT) ) + { + wxLogWarning("Failed to initialize the default system locale."); + } + + + // Independently of whether we succeeded to set the locale or not, try + // to load the translations (for the default system language) here. + // normally this wouldn't be necessary as the catalog files would be found // in the default locations, but when the program is not installed the // catalogs are in the build directory where we wouldn't find them by From b6d4eda4ad14e22a8168c9f9baccad3f289d46a7 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Fri, 13 Aug 2021 19:09:13 +0200 Subject: [PATCH 12/28] Extract wxLOCALE_XXX constants into their own header No real changes, just make it possible to use these constants without including the entire wx/intl.h. Note that the existing headers including wx/intl.h need to keep including it, unfortunately, as not doing it any longer would break compilation of any code including them which relies on _() or wxGetTranslation() being defined after including e.g. wx/dc.h. This was, of course, never guaranteed, but in practice it worked for a very long time, so don't break it now. This commit is best viewed with --color-moved git option. --- Makefile.in | 2 + build/bakefiles/files.bkl | 1 + build/cmake/files.cmake | 1 + build/files | 1 + build/msw/wx_base.vcxproj | 1 + build/msw/wx_base.vcxproj.filters | 3 ++ build/msw/wx_vc8_base.vcproj | 4 ++ build/msw/wx_vc9_base.vcproj | 4 ++ include/wx/intl.h | 57 +---------------------- include/wx/localedefs.h | 77 +++++++++++++++++++++++++++++++ 10 files changed, 95 insertions(+), 56 deletions(-) create mode 100644 include/wx/localedefs.h diff --git a/Makefile.in b/Makefile.in index 3ce1f73320..c24df6bdc2 100644 --- a/Makefile.in +++ b/Makefile.in @@ -581,6 +581,7 @@ ALL_BASE_HEADERS = \ wx/generic/fswatcher.h \ wx/secretstore.h \ wx/lzmastream.h \ + wx/localedefs.h \ $(BASE_PLATFORM_HDR) \ wx/fs_inet.h \ wx/protocol/file.h \ @@ -766,6 +767,7 @@ ALL_PORTS_BASE_HEADERS = \ wx/generic/fswatcher.h \ wx/secretstore.h \ wx/lzmastream.h \ + wx/localedefs.h \ wx/unix/app.h \ wx/unix/apptbase.h \ wx/unix/apptrait.h \ diff --git a/build/bakefiles/files.bkl b/build/bakefiles/files.bkl index ab4f770305..32dca4cde8 100644 --- a/build/bakefiles/files.bkl +++ b/build/bakefiles/files.bkl @@ -735,6 +735,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! wx/generic/fswatcher.h wx/secretstore.h wx/lzmastream.h + wx/localedefs.h diff --git a/build/cmake/files.cmake b/build/cmake/files.cmake index 3b90eda592..535259b3a5 100644 --- a/build/cmake/files.cmake +++ b/build/cmake/files.cmake @@ -651,6 +651,7 @@ set(BASE_CMN_HDR wx/fswatcher.h wx/generic/fswatcher.h wx/lzmastream.h + wx/localedefs.h ) set(NET_UNIX_SRC diff --git a/build/files b/build/files index 5c68b80c8d..574cbb6e37 100644 --- a/build/files +++ b/build/files @@ -574,6 +574,7 @@ BASE_CMN_HDR = wx/link.h wx/list.h wx/listimpl.cpp + wx/localedefs.h wx/log.h wx/longlong.h wx/lzmastream.h diff --git a/build/msw/wx_base.vcxproj b/build/msw/wx_base.vcxproj index 102a6974d7..8f8c9ae262 100644 --- a/build/msw/wx_base.vcxproj +++ b/build/msw/wx_base.vcxproj @@ -823,6 +823,7 @@ + diff --git a/build/msw/wx_base.vcxproj.filters b/build/msw/wx_base.vcxproj.filters index 44e8f07935..4c57355ba1 100644 --- a/build/msw/wx_base.vcxproj.filters +++ b/build/msw/wx_base.vcxproj.filters @@ -598,6 +598,9 @@ Common Headers + + Common Headers + Common Headers diff --git a/build/msw/wx_vc8_base.vcproj b/build/msw/wx_vc8_base.vcproj index 5708485856..69963dce91 100644 --- a/build/msw/wx_vc8_base.vcproj +++ b/build/msw/wx_vc8_base.vcproj @@ -2103,6 +2103,10 @@ RelativePath="..\..\include\wx\list.h" > + + diff --git a/build/msw/wx_vc9_base.vcproj b/build/msw/wx_vc9_base.vcproj index 1accda8c00..1776e4de02 100644 --- a/build/msw/wx_vc9_base.vcproj +++ b/build/msw/wx_vc9_base.vcproj @@ -2099,6 +2099,10 @@ RelativePath="..\..\include\wx\list.h" > + + diff --git a/include/wx/intl.h b/include/wx/intl.h index 2ce148dd54..b5c3458d6c 100644 --- a/include/wx/intl.h +++ b/include/wx/intl.h @@ -13,19 +13,10 @@ #define _WX_INTL_H_ #include "wx/defs.h" +#include "wx/localedefs.h" #include "wx/string.h" #include "wx/translation.h" -// Make wxLayoutDirection enum available without need for wxUSE_INTL so wxWindow, wxApp -// and other classes are not distrubed by wxUSE_INTL - -enum wxLayoutDirection -{ - wxLayout_Default, - wxLayout_LeftToRight, - wxLayout_RightToLeft -}; - #if wxUSE_INTL #include "wx/fontenc.h" @@ -84,52 +75,6 @@ struct WXDLLIMPEXP_BASE wxLanguageInfo const char* TrySetLocale() const; }; -// ---------------------------------------------------------------------------- -// wxLocaleCategory: the category of locale settings -// ---------------------------------------------------------------------------- - -enum wxLocaleCategory -{ - // (any) numbers - wxLOCALE_CAT_NUMBER, - - // date/time - wxLOCALE_CAT_DATE, - - // monetary value - wxLOCALE_CAT_MONEY, - - // default category for wxLocaleInfo values which only apply to a single - // category (e.g. wxLOCALE_SHORT_DATE_FMT) - wxLOCALE_CAT_DEFAULT, - - wxLOCALE_CAT_MAX -}; - -// ---------------------------------------------------------------------------- -// wxLocaleInfo: the items understood by wxLocale::GetInfo() -// ---------------------------------------------------------------------------- - -enum wxLocaleInfo -{ - // the thousands separator (for wxLOCALE_CAT_NUMBER or MONEY) - wxLOCALE_THOUSANDS_SEP, - - // the character used as decimal point (for wxLOCALE_CAT_NUMBER or MONEY) - wxLOCALE_DECIMAL_POINT, - - // the stftime()-formats used for short/long date and time representations - // (under some platforms short and long date formats are the same) - // - // NB: these elements should appear in this order, code in GetInfo() relies - // on it - wxLOCALE_SHORT_DATE_FMT, - wxLOCALE_LONG_DATE_FMT, - wxLOCALE_DATE_TIME_FMT, - wxLOCALE_TIME_FMT - -}; - // ---------------------------------------------------------------------------- // wxLocale: encapsulates all language dependent settings, including current // message catalogs, date, time and currency formats (TODO) &c diff --git a/include/wx/localedefs.h b/include/wx/localedefs.h new file mode 100644 index 0000000000..727c79bbd0 --- /dev/null +++ b/include/wx/localedefs.h @@ -0,0 +1,77 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/localedefs.h +// Purpose: Definitions of common locale-related constants +// Author: Vadim Zeitlin +// Created: 2021-07-31 (extracted from wx/intl.h) +// Copyright: (c) 2021 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_LOCALEDEFS_H_ +#define _WX_LOCALEDEFS_H_ + +// ---------------------------------------------------------------------------- +// wxLayoutDirection: used by wxWindow, wxDC etc +// ---------------------------------------------------------------------------- + +// Note that this one must be available even when wxUSE_INTL == 0 as it's used +// outside of locale code too. + +enum wxLayoutDirection +{ + wxLayout_Default, + wxLayout_LeftToRight, + wxLayout_RightToLeft +}; + +#if wxUSE_INTL + +// ---------------------------------------------------------------------------- +// wxLocaleCategory: the category of locale settings +// ---------------------------------------------------------------------------- + +enum wxLocaleCategory +{ + // (any) numbers + wxLOCALE_CAT_NUMBER, + + // date/time + wxLOCALE_CAT_DATE, + + // monetary value + wxLOCALE_CAT_MONEY, + + // default category for wxLocaleInfo values which only apply to a single + // category (e.g. wxLOCALE_SHORT_DATE_FMT) + wxLOCALE_CAT_DEFAULT, + + wxLOCALE_CAT_MAX +}; + +// ---------------------------------------------------------------------------- +// wxLocaleInfo: the items understood by wxLocale::GetInfo() +// ---------------------------------------------------------------------------- + +enum wxLocaleInfo +{ + // the thousands separator (for wxLOCALE_CAT_NUMBER or MONEY) + wxLOCALE_THOUSANDS_SEP, + + // the character used as decimal point (for wxLOCALE_CAT_NUMBER or MONEY) + wxLOCALE_DECIMAL_POINT, + + // the stftime()-formats used for short/long date and time representations + // (under some platforms short and long date formats are the same) + // + // NB: these elements should appear in this order, code in GetInfo() relies + // on it + wxLOCALE_SHORT_DATE_FMT, + wxLOCALE_LONG_DATE_FMT, + wxLOCALE_DATE_TIME_FMT, + wxLOCALE_TIME_FMT + +}; + +#endif // wxUSE_INTL + +#endif // _WX_LOCALEDEFS_H_ From b12961f992b180d5e394d3bd0d6a6d4a2e579421 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Fri, 13 Aug 2021 23:15:49 +0200 Subject: [PATCH 13/28] Display locale information directly in the main sample frame This is more convenient than having to open the "About" dialog to see the details of the locale being used. It also makes it unnecessary to store wxLocale reference in the frame class, simplifying the sample code. --- samples/internat/internat.cpp | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/samples/internat/internat.cpp b/samples/internat/internat.cpp index 82e80f9e98..21abd20e1c 100644 --- a/samples/internat/internat.cpp +++ b/samples/internat/internat.cpp @@ -100,8 +100,6 @@ public: void OnTestMsgBox(wxCommandEvent& event); wxDECLARE_EVENT_TABLE(); - - wxLocale& m_locale; }; // ---------------------------------------------------------------------------- @@ -290,8 +288,7 @@ bool MyApp::OnInit() MyFrame::MyFrame(wxLocale& locale) : wxFrame(NULL, wxID_ANY, - _("International wxWidgets App")), - m_locale(locale) + _("International wxWidgets App")) { SetIcon(wxICON(sample)); @@ -353,9 +350,20 @@ MyFrame::MyFrame(wxLocale& locale) wxPanel* const panel = new wxPanel(this); - // create some controls affected by the locale wxSizer* const topSizer = new wxBoxSizer(wxVERTICAL); + wxString localeInfo; + wxString locale = locale.GetLocale(); + wxString sysname = locale.GetSysName(); + wxString canname = locale.GetCanonicalName(); + localeInfo.Printf("Current locale: %s (system name: %s, canonical name: %s)", + locale, sysname, canname ); + + topSizer->Add(new wxStaticText(panel, wxID_ANY, localeInfo), + wxSizerFlags().Center().Border()); + + // create some controls affected by the locale + // this demonstrates RTL layout mirroring for Arabic locales and using // locale-specific decimal separator in wxSpinCtrlDouble. wxSizer *sizer = new wxBoxSizer(wxHORIZONTAL); @@ -400,20 +408,10 @@ void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event) ) void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) { - wxString localeInfo; - wxString locale = m_locale.GetLocale(); - wxString sysname = m_locale.GetSysName(); - wxString canname = m_locale.GetCanonicalName(); - - localeInfo.Printf(_("Language: %s\nSystem locale name: %s\nCanonical locale name: %s\n"), - locale, sysname, canname ); - wxMessageDialog dlg( this, - wxString(_("I18n sample\n(c) 1998, 1999 Vadim Zeitlin and Julian Smart")) - + "\n\n" - + localeInfo, - _("About Internat"), + _("I18n sample\n(c) 1998, 1999 Vadim Zeitlin and Julian Smart"), + _("About Internat"), wxOK | wxICON_INFORMATION ); dlg.ShowModal(); From b9cbe6770f9750c69253f0abda1001ca45c0240c Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Fri, 13 Aug 2021 23:29:42 +0200 Subject: [PATCH 14/28] Add wxUILocale with minimal functionality Use it in the sample to show what (little) it can do right now. --- Makefile.in | 102 +++++++++++++++++++--- build/bakefiles/files.bkl | 5 ++ build/cmake/files.cmake | 5 ++ build/files | 5 ++ build/msw/makefile.gcc | 32 +++++++ build/msw/makefile.vc | 32 +++++++ build/msw/wx_base.vcxproj | 21 +++++ build/msw/wx_base.vcxproj.filters | 9 ++ build/msw/wx_vc8_base.vcproj | 140 ++++++++++++++++++++++++++++++ build/msw/wx_vc9_base.vcproj | 140 ++++++++++++++++++++++++++++++ include/wx/intl.h | 2 + include/wx/private/uilocale.h | 43 +++++++++ include/wx/uilocale.h | 66 ++++++++++++++ interface/wx/intl.h | 14 ++- interface/wx/uilocale.h | 106 ++++++++++++++++++++++ samples/internat/internat.cpp | 33 +++---- src/common/intl.cpp | 107 ++++++++++++++--------- src/common/uilocale.cpp | 90 +++++++++++++++++++ src/msw/uilocale.cpp | 101 +++++++++++++++++++++ src/osx/core/uilocale.cpp | 92 ++++++++++++++++++++ src/unix/uilocale.cpp | 91 +++++++++++++++++++ tests/intl/intltest.cpp | 14 +++ 22 files changed, 1178 insertions(+), 72 deletions(-) create mode 100644 include/wx/private/uilocale.h create mode 100644 include/wx/uilocale.h create mode 100644 interface/wx/uilocale.h create mode 100644 src/common/uilocale.cpp create mode 100644 src/msw/uilocale.cpp create mode 100644 src/osx/core/uilocale.cpp create mode 100644 src/unix/uilocale.cpp diff --git a/Makefile.in b/Makefile.in index c24df6bdc2..519cf77147 100644 --- a/Makefile.in +++ b/Makefile.in @@ -582,6 +582,7 @@ ALL_BASE_HEADERS = \ wx/secretstore.h \ wx/lzmastream.h \ wx/localedefs.h \ + wx/uilocale.h \ $(BASE_PLATFORM_HDR) \ wx/fs_inet.h \ wx/protocol/file.h \ @@ -768,6 +769,7 @@ ALL_PORTS_BASE_HEADERS = \ wx/secretstore.h \ wx/lzmastream.h \ wx/localedefs.h \ + wx/uilocale.h \ wx/unix/app.h \ wx/unix/apptbase.h \ wx/unix/apptrait.h \ @@ -907,6 +909,7 @@ ALL_BASE_SOURCES = \ src/generic/fswatcherg.cpp \ src/common/secretstore.cpp \ src/common/lzmastream.cpp \ + src/common/uilocale.cpp \ src/common/fdiodispatcher.cpp \ src/common/selectdispatcher.cpp \ src/unix/appunix.cpp \ @@ -926,6 +929,7 @@ ALL_BASE_SOURCES = \ src/unix/fswatcher_inotify.cpp \ src/unix/stdpaths.cpp \ src/unix/secretstore.cpp \ + src/unix/uilocale.cpp \ src/msw/basemsw.cpp \ src/msw/crashrpt.cpp \ src/msw/debughlp.cpp \ @@ -946,6 +950,7 @@ ALL_BASE_SOURCES = \ src/msw/utilsexc.cpp \ src/msw/fswatcher.cpp \ src/msw/secretstore.cpp \ + src/msw/uilocale.cpp \ $(BASE_OSX_SRC) \ src/common/event.cpp \ src/common/fs_mem.cpp \ @@ -1095,6 +1100,7 @@ MONODLL_OBJECTS = \ monodll_fswatcherg.o \ monodll_common_secretstore.o \ monodll_lzmastream.o \ + monodll_common_uilocale.o \ $(__BASE_PLATFORM_SRC_OBJECTS) \ monodll_event.o \ monodll_fs_mem.o \ @@ -1237,6 +1243,7 @@ MONOLIB_OBJECTS = \ monolib_fswatcherg.o \ monolib_common_secretstore.o \ monolib_lzmastream.o \ + monolib_common_uilocale.o \ $(__BASE_PLATFORM_SRC_OBJECTS_1) \ monolib_event.o \ monolib_fs_mem.o \ @@ -1367,6 +1374,7 @@ BASEDLL_OBJECTS = \ basedll_fswatcherg.o \ basedll_common_secretstore.o \ basedll_lzmastream.o \ + basedll_common_uilocale.o \ $(__BASE_PLATFORM_SRC_OBJECTS_2) \ basedll_event.o \ basedll_fs_mem.o \ @@ -1479,6 +1487,7 @@ BASELIB_OBJECTS = \ baselib_fswatcherg.o \ baselib_common_secretstore.o \ baselib_lzmastream.o \ + baselib_common_uilocale.o \ $(__BASE_PLATFORM_SRC_OBJECTS_3) \ baselib_event.o \ baselib_fs_mem.o \ @@ -2359,6 +2368,7 @@ COND_TOOLKIT_OSX_COCOA_BASE_OSX_SRC = \ src/osx/core/strconv_cf.cpp \ src/osx/cocoa/utils_base.mm \ src/osx/core/secretstore.cpp \ + src/osx/core/uilocale.cpp \ src/common/fdiodispatcher.cpp \ src/common/selectdispatcher.cpp \ src/unix/appunix.cpp \ @@ -2384,6 +2394,7 @@ COND_TOOLKIT_OSX_IPHONE_BASE_OSX_SRC = \ src/osx/core/strconv_cf.cpp \ src/osx/cocoa/utils_base.mm \ src/osx/core/secretstore.cpp \ + src/osx/core/uilocale.cpp \ src/common/fdiodispatcher.cpp \ src/common/selectdispatcher.cpp \ src/unix/appunix.cpp \ @@ -2423,7 +2434,8 @@ COND_TOOLKIT_COCOA_BASE_OSX_SRC = \ src/osx/core/evtloop_cf.cpp \ src/osx/core/strconv_cf.cpp \ src/osx/cocoa/utils_base.mm \ - src/osx/core/secretstore.cpp + src/osx/core/secretstore.cpp \ + src/osx/core/uilocale.cpp @COND_TOOLKIT_COCOA@BASE_OSX_SRC = $(COND_TOOLKIT_COCOA_BASE_OSX_SRC) COND_TOOLKIT_GTK_BASE_OSX_SRC = \ src/common/fdiodispatcher.cpp \ @@ -2446,7 +2458,8 @@ COND_TOOLKIT_GTK_BASE_OSX_SRC = \ src/osx/core/evtloop_cf.cpp \ src/osx/core/strconv_cf.cpp \ src/osx/cocoa/utils_base.mm \ - src/osx/core/secretstore.cpp + src/osx/core/secretstore.cpp \ + src/osx/core/uilocale.cpp @COND_TOOLKIT_GTK@BASE_OSX_SRC = $(COND_TOOLKIT_GTK_BASE_OSX_SRC) COND_TOOLKIT_X11_BASE_OSX_SRC = \ src/common/fdiodispatcher.cpp \ @@ -2469,7 +2482,8 @@ COND_TOOLKIT_X11_BASE_OSX_SRC = \ src/osx/core/evtloop_cf.cpp \ src/osx/core/strconv_cf.cpp \ src/osx/cocoa/utils_base.mm \ - src/osx/core/secretstore.cpp + src/osx/core/secretstore.cpp \ + src/osx/core/uilocale.cpp @COND_TOOLKIT_X11@BASE_OSX_SRC = $(COND_TOOLKIT_X11_BASE_OSX_SRC) COND_TOOLKIT_MOTIF_BASE_OSX_SRC = \ src/common/fdiodispatcher.cpp \ @@ -2492,7 +2506,8 @@ COND_TOOLKIT_MOTIF_BASE_OSX_SRC = \ src/osx/core/evtloop_cf.cpp \ src/osx/core/strconv_cf.cpp \ src/osx/cocoa/utils_base.mm \ - src/osx/core/secretstore.cpp + src/osx/core/secretstore.cpp \ + src/osx/core/uilocale.cpp @COND_TOOLKIT_MOTIF@BASE_OSX_SRC = $(COND_TOOLKIT_MOTIF_BASE_OSX_SRC) COND_TOOLKIT__BASE_OSX_SRC = \ src/common/fdiodispatcher.cpp \ @@ -2515,7 +2530,8 @@ COND_TOOLKIT__BASE_OSX_SRC = \ src/osx/core/evtloop_cf.cpp \ src/osx/core/strconv_cf.cpp \ src/osx/cocoa/utils_base.mm \ - src/osx/core/secretstore.cpp + src/osx/core/secretstore.cpp \ + src/osx/core/uilocale.cpp @COND_TOOLKIT_@BASE_OSX_SRC = $(COND_TOOLKIT__BASE_OSX_SRC) COND_TOOLKIT_OSX_COCOA_BASE_OSX_HDR = \ wx/osx/core/cfdataref.h \ @@ -4261,6 +4277,7 @@ COND_PLATFORM_MACOSX_1___BASE_PLATFORM_SRC_OBJECTS = \ monodll_strconv_cf.o \ monodll_utils_base.o \ monodll_core_secretstore.o \ + monodll_core_uilocale.o \ monodll_fdiodispatcher.o \ monodll_selectdispatcher.o \ monodll_appunix.o \ @@ -4298,7 +4315,8 @@ COND_PLATFORM_UNIX_1___BASE_PLATFORM_SRC_OBJECTS = \ monodll_unix_mimetype.o \ monodll_fswatcher_inotify.o \ monodll_unix_stdpaths.o \ - monodll_unix_secretstore.o + monodll_unix_secretstore.o \ + monodll_unix_uilocale.o @COND_PLATFORM_UNIX_1@__BASE_PLATFORM_SRC_OBJECTS = $(COND_PLATFORM_UNIX_1___BASE_PLATFORM_SRC_OBJECTS) COND_PLATFORM_WIN32_1___BASE_PLATFORM_SRC_OBJECTS = \ monodll_basemsw.o \ @@ -4320,7 +4338,8 @@ COND_PLATFORM_WIN32_1___BASE_PLATFORM_SRC_OBJECTS = \ monodll_msw_utils.o \ monodll_utilsexc.o \ monodll_fswatcher.o \ - monodll_msw_secretstore.o + monodll_msw_secretstore.o \ + monodll_msw_uilocale.o @COND_PLATFORM_WIN32_1@__BASE_PLATFORM_SRC_OBJECTS = $(COND_PLATFORM_WIN32_1___BASE_PLATFORM_SRC_OBJECTS) @COND_PLATFORM_WIN32_1@__BASE_AND_GUI_PLATFORM_SRC_OBJECTS \ @COND_PLATFORM_WIN32_1@ = monodll_msw_main.o monodll_volume.o @@ -6254,6 +6273,7 @@ COND_PLATFORM_MACOSX_1___BASE_PLATFORM_SRC_OBJECTS_1 = \ monolib_strconv_cf.o \ monolib_utils_base.o \ monolib_core_secretstore.o \ + monolib_core_uilocale.o \ monolib_fdiodispatcher.o \ monolib_selectdispatcher.o \ monolib_appunix.o \ @@ -6291,7 +6311,8 @@ COND_PLATFORM_UNIX_1___BASE_PLATFORM_SRC_OBJECTS_1 = \ monolib_unix_mimetype.o \ monolib_fswatcher_inotify.o \ monolib_unix_stdpaths.o \ - monolib_unix_secretstore.o + monolib_unix_secretstore.o \ + monolib_unix_uilocale.o @COND_PLATFORM_UNIX_1@__BASE_PLATFORM_SRC_OBJECTS_1 = $(COND_PLATFORM_UNIX_1___BASE_PLATFORM_SRC_OBJECTS_1) COND_PLATFORM_WIN32_1___BASE_PLATFORM_SRC_OBJECTS_1 = \ monolib_basemsw.o \ @@ -6313,7 +6334,8 @@ COND_PLATFORM_WIN32_1___BASE_PLATFORM_SRC_OBJECTS_1 = \ monolib_msw_utils.o \ monolib_utilsexc.o \ monolib_fswatcher.o \ - monolib_msw_secretstore.o + monolib_msw_secretstore.o \ + monolib_msw_uilocale.o @COND_PLATFORM_WIN32_1@__BASE_PLATFORM_SRC_OBJECTS_1 = $(COND_PLATFORM_WIN32_1___BASE_PLATFORM_SRC_OBJECTS_1) @COND_PLATFORM_WIN32_1@__BASE_AND_GUI_PLATFORM_SRC_OBJECTS_1 \ @COND_PLATFORM_WIN32_1@ = monolib_msw_main.o monolib_volume.o @@ -8299,6 +8321,7 @@ COND_PLATFORM_MACOSX_1___BASE_PLATFORM_SRC_OBJECTS_2 = \ basedll_strconv_cf.o \ basedll_utils_base.o \ basedll_core_secretstore.o \ + basedll_core_uilocale.o \ basedll_fdiodispatcher.o \ basedll_selectdispatcher.o \ basedll_appunix.o \ @@ -8336,7 +8359,8 @@ COND_PLATFORM_UNIX_1___BASE_PLATFORM_SRC_OBJECTS_2 = \ basedll_unix_mimetype.o \ basedll_fswatcher_inotify.o \ basedll_unix_stdpaths.o \ - basedll_unix_secretstore.o + basedll_unix_secretstore.o \ + basedll_unix_uilocale.o @COND_PLATFORM_UNIX_1@__BASE_PLATFORM_SRC_OBJECTS_2 = $(COND_PLATFORM_UNIX_1___BASE_PLATFORM_SRC_OBJECTS_2) COND_PLATFORM_WIN32_1___BASE_PLATFORM_SRC_OBJECTS_2 = \ basedll_basemsw.o \ @@ -8358,7 +8382,8 @@ COND_PLATFORM_WIN32_1___BASE_PLATFORM_SRC_OBJECTS_2 = \ basedll_msw_utils.o \ basedll_utilsexc.o \ basedll_fswatcher.o \ - basedll_msw_secretstore.o + basedll_msw_secretstore.o \ + basedll_msw_uilocale.o @COND_PLATFORM_WIN32_1@__BASE_PLATFORM_SRC_OBJECTS_2 = $(COND_PLATFORM_WIN32_1___BASE_PLATFORM_SRC_OBJECTS_2) @COND_PLATFORM_WIN32_1@__BASE_AND_GUI_PLATFORM_SRC_OBJECTS_2 \ @COND_PLATFORM_WIN32_1@ = basedll_main.o basedll_volume.o @@ -8382,6 +8407,7 @@ COND_PLATFORM_MACOSX_1___BASE_PLATFORM_SRC_OBJECTS_3 = \ baselib_strconv_cf.o \ baselib_utils_base.o \ baselib_core_secretstore.o \ + baselib_core_uilocale.o \ baselib_fdiodispatcher.o \ baselib_selectdispatcher.o \ baselib_appunix.o \ @@ -8419,7 +8445,8 @@ COND_PLATFORM_UNIX_1___BASE_PLATFORM_SRC_OBJECTS_3 = \ baselib_unix_mimetype.o \ baselib_fswatcher_inotify.o \ baselib_unix_stdpaths.o \ - baselib_unix_secretstore.o + baselib_unix_secretstore.o \ + baselib_unix_uilocale.o @COND_PLATFORM_UNIX_1@__BASE_PLATFORM_SRC_OBJECTS_3 = $(COND_PLATFORM_UNIX_1___BASE_PLATFORM_SRC_OBJECTS_3) COND_PLATFORM_WIN32_1___BASE_PLATFORM_SRC_OBJECTS_3 = \ baselib_basemsw.o \ @@ -8441,7 +8468,8 @@ COND_PLATFORM_WIN32_1___BASE_PLATFORM_SRC_OBJECTS_3 = \ baselib_msw_utils.o \ baselib_utilsexc.o \ baselib_fswatcher.o \ - baselib_msw_secretstore.o + baselib_msw_secretstore.o \ + baselib_msw_uilocale.o @COND_PLATFORM_WIN32_1@__BASE_PLATFORM_SRC_OBJECTS_3 = $(COND_PLATFORM_WIN32_1___BASE_PLATFORM_SRC_OBJECTS_3) @COND_PLATFORM_WIN32_1@__BASE_AND_GUI_PLATFORM_SRC_OBJECTS_3 \ @COND_PLATFORM_WIN32_1@ = baselib_main.o baselib_volume.o @@ -15997,6 +16025,9 @@ monodll_common_secretstore.o: $(srcdir)/src/common/secretstore.cpp $(MONODLL_ODE monodll_lzmastream.o: $(srcdir)/src/common/lzmastream.cpp $(MONODLL_ODEP) $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/common/lzmastream.cpp +monodll_common_uilocale.o: $(srcdir)/src/common/uilocale.cpp $(MONODLL_ODEP) + $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/common/uilocale.cpp + monodll_unix_mimetype.o: $(srcdir)/src/unix/mimetype.cpp $(MONODLL_ODEP) $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/unix/mimetype.cpp @@ -16009,6 +16040,9 @@ monodll_unix_stdpaths.o: $(srcdir)/src/unix/stdpaths.cpp $(MONODLL_ODEP) monodll_unix_secretstore.o: $(srcdir)/src/unix/secretstore.cpp $(MONODLL_ODEP) $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/unix/secretstore.cpp +monodll_unix_uilocale.o: $(srcdir)/src/unix/uilocale.cpp $(MONODLL_ODEP) + $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/unix/uilocale.cpp + monodll_basemsw.o: $(srcdir)/src/msw/basemsw.cpp $(MONODLL_ODEP) $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/msw/basemsw.cpp @@ -16069,6 +16103,9 @@ monodll_fswatcher.o: $(srcdir)/src/msw/fswatcher.cpp $(MONODLL_ODEP) monodll_msw_secretstore.o: $(srcdir)/src/msw/secretstore.cpp $(MONODLL_ODEP) $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/msw/secretstore.cpp +monodll_msw_uilocale.o: $(srcdir)/src/msw/uilocale.cpp $(MONODLL_ODEP) + $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/msw/uilocale.cpp + monodll_core_mimetype.o: $(srcdir)/src/osx/core/mimetype.cpp $(MONODLL_ODEP) $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/osx/core/mimetype.cpp @@ -16087,6 +16124,9 @@ monodll_utils_base.o: $(srcdir)/src/osx/cocoa/utils_base.mm $(MONODLL_ODEP) monodll_core_secretstore.o: $(srcdir)/src/osx/core/secretstore.cpp $(MONODLL_ODEP) $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/osx/core/secretstore.cpp +monodll_core_uilocale.o: $(srcdir)/src/osx/core/uilocale.cpp $(MONODLL_ODEP) + $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/osx/core/uilocale.cpp + monodll_fswatcher_fsevents.o: $(srcdir)/src/osx/fswatcher_fsevents.cpp $(MONODLL_ODEP) $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/osx/fswatcher_fsevents.cpp @@ -21274,6 +21314,9 @@ monolib_common_secretstore.o: $(srcdir)/src/common/secretstore.cpp $(MONOLIB_ODE monolib_lzmastream.o: $(srcdir)/src/common/lzmastream.cpp $(MONOLIB_ODEP) $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/common/lzmastream.cpp +monolib_common_uilocale.o: $(srcdir)/src/common/uilocale.cpp $(MONOLIB_ODEP) + $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/common/uilocale.cpp + monolib_unix_mimetype.o: $(srcdir)/src/unix/mimetype.cpp $(MONOLIB_ODEP) $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/unix/mimetype.cpp @@ -21286,6 +21329,9 @@ monolib_unix_stdpaths.o: $(srcdir)/src/unix/stdpaths.cpp $(MONOLIB_ODEP) monolib_unix_secretstore.o: $(srcdir)/src/unix/secretstore.cpp $(MONOLIB_ODEP) $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/unix/secretstore.cpp +monolib_unix_uilocale.o: $(srcdir)/src/unix/uilocale.cpp $(MONOLIB_ODEP) + $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/unix/uilocale.cpp + monolib_basemsw.o: $(srcdir)/src/msw/basemsw.cpp $(MONOLIB_ODEP) $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/msw/basemsw.cpp @@ -21346,6 +21392,9 @@ monolib_fswatcher.o: $(srcdir)/src/msw/fswatcher.cpp $(MONOLIB_ODEP) monolib_msw_secretstore.o: $(srcdir)/src/msw/secretstore.cpp $(MONOLIB_ODEP) $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/msw/secretstore.cpp +monolib_msw_uilocale.o: $(srcdir)/src/msw/uilocale.cpp $(MONOLIB_ODEP) + $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/msw/uilocale.cpp + monolib_core_mimetype.o: $(srcdir)/src/osx/core/mimetype.cpp $(MONOLIB_ODEP) $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/osx/core/mimetype.cpp @@ -21364,6 +21413,9 @@ monolib_utils_base.o: $(srcdir)/src/osx/cocoa/utils_base.mm $(MONOLIB_ODEP) monolib_core_secretstore.o: $(srcdir)/src/osx/core/secretstore.cpp $(MONOLIB_ODEP) $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/osx/core/secretstore.cpp +monolib_core_uilocale.o: $(srcdir)/src/osx/core/uilocale.cpp $(MONOLIB_ODEP) + $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/osx/core/uilocale.cpp + monolib_fswatcher_fsevents.o: $(srcdir)/src/osx/fswatcher_fsevents.cpp $(MONOLIB_ODEP) $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/osx/fswatcher_fsevents.cpp @@ -26551,6 +26603,9 @@ basedll_common_secretstore.o: $(srcdir)/src/common/secretstore.cpp $(BASEDLL_ODE basedll_lzmastream.o: $(srcdir)/src/common/lzmastream.cpp $(BASEDLL_ODEP) $(CXXC) -c -o $@ $(BASEDLL_CXXFLAGS) $(srcdir)/src/common/lzmastream.cpp +basedll_common_uilocale.o: $(srcdir)/src/common/uilocale.cpp $(BASEDLL_ODEP) + $(CXXC) -c -o $@ $(BASEDLL_CXXFLAGS) $(srcdir)/src/common/uilocale.cpp + basedll_unix_mimetype.o: $(srcdir)/src/unix/mimetype.cpp $(BASEDLL_ODEP) $(CXXC) -c -o $@ $(BASEDLL_CXXFLAGS) $(srcdir)/src/unix/mimetype.cpp @@ -26563,6 +26618,9 @@ basedll_unix_stdpaths.o: $(srcdir)/src/unix/stdpaths.cpp $(BASEDLL_ODEP) basedll_unix_secretstore.o: $(srcdir)/src/unix/secretstore.cpp $(BASEDLL_ODEP) $(CXXC) -c -o $@ $(BASEDLL_CXXFLAGS) $(srcdir)/src/unix/secretstore.cpp +basedll_unix_uilocale.o: $(srcdir)/src/unix/uilocale.cpp $(BASEDLL_ODEP) + $(CXXC) -c -o $@ $(BASEDLL_CXXFLAGS) $(srcdir)/src/unix/uilocale.cpp + basedll_basemsw.o: $(srcdir)/src/msw/basemsw.cpp $(BASEDLL_ODEP) $(CXXC) -c -o $@ $(BASEDLL_CXXFLAGS) $(srcdir)/src/msw/basemsw.cpp @@ -26623,6 +26681,9 @@ basedll_fswatcher.o: $(srcdir)/src/msw/fswatcher.cpp $(BASEDLL_ODEP) basedll_msw_secretstore.o: $(srcdir)/src/msw/secretstore.cpp $(BASEDLL_ODEP) $(CXXC) -c -o $@ $(BASEDLL_CXXFLAGS) $(srcdir)/src/msw/secretstore.cpp +basedll_msw_uilocale.o: $(srcdir)/src/msw/uilocale.cpp $(BASEDLL_ODEP) + $(CXXC) -c -o $@ $(BASEDLL_CXXFLAGS) $(srcdir)/src/msw/uilocale.cpp + basedll_core_mimetype.o: $(srcdir)/src/osx/core/mimetype.cpp $(BASEDLL_ODEP) $(CXXC) -c -o $@ $(BASEDLL_CXXFLAGS) $(srcdir)/src/osx/core/mimetype.cpp @@ -26641,6 +26702,9 @@ basedll_utils_base.o: $(srcdir)/src/osx/cocoa/utils_base.mm $(BASEDLL_ODEP) basedll_core_secretstore.o: $(srcdir)/src/osx/core/secretstore.cpp $(BASEDLL_ODEP) $(CXXC) -c -o $@ $(BASEDLL_CXXFLAGS) $(srcdir)/src/osx/core/secretstore.cpp +basedll_core_uilocale.o: $(srcdir)/src/osx/core/uilocale.cpp $(BASEDLL_ODEP) + $(CXXC) -c -o $@ $(BASEDLL_CXXFLAGS) $(srcdir)/src/osx/core/uilocale.cpp + basedll_fswatcher_fsevents.o: $(srcdir)/src/osx/fswatcher_fsevents.cpp $(BASEDLL_ODEP) $(CXXC) -c -o $@ $(BASEDLL_CXXFLAGS) $(srcdir)/src/osx/fswatcher_fsevents.cpp @@ -27025,6 +27089,9 @@ baselib_common_secretstore.o: $(srcdir)/src/common/secretstore.cpp $(BASELIB_ODE baselib_lzmastream.o: $(srcdir)/src/common/lzmastream.cpp $(BASELIB_ODEP) $(CXXC) -c -o $@ $(BASELIB_CXXFLAGS) $(srcdir)/src/common/lzmastream.cpp +baselib_common_uilocale.o: $(srcdir)/src/common/uilocale.cpp $(BASELIB_ODEP) + $(CXXC) -c -o $@ $(BASELIB_CXXFLAGS) $(srcdir)/src/common/uilocale.cpp + baselib_unix_mimetype.o: $(srcdir)/src/unix/mimetype.cpp $(BASELIB_ODEP) $(CXXC) -c -o $@ $(BASELIB_CXXFLAGS) $(srcdir)/src/unix/mimetype.cpp @@ -27037,6 +27104,9 @@ baselib_unix_stdpaths.o: $(srcdir)/src/unix/stdpaths.cpp $(BASELIB_ODEP) baselib_unix_secretstore.o: $(srcdir)/src/unix/secretstore.cpp $(BASELIB_ODEP) $(CXXC) -c -o $@ $(BASELIB_CXXFLAGS) $(srcdir)/src/unix/secretstore.cpp +baselib_unix_uilocale.o: $(srcdir)/src/unix/uilocale.cpp $(BASELIB_ODEP) + $(CXXC) -c -o $@ $(BASELIB_CXXFLAGS) $(srcdir)/src/unix/uilocale.cpp + baselib_basemsw.o: $(srcdir)/src/msw/basemsw.cpp $(BASELIB_ODEP) $(CXXC) -c -o $@ $(BASELIB_CXXFLAGS) $(srcdir)/src/msw/basemsw.cpp @@ -27097,6 +27167,9 @@ baselib_fswatcher.o: $(srcdir)/src/msw/fswatcher.cpp $(BASELIB_ODEP) baselib_msw_secretstore.o: $(srcdir)/src/msw/secretstore.cpp $(BASELIB_ODEP) $(CXXC) -c -o $@ $(BASELIB_CXXFLAGS) $(srcdir)/src/msw/secretstore.cpp +baselib_msw_uilocale.o: $(srcdir)/src/msw/uilocale.cpp $(BASELIB_ODEP) + $(CXXC) -c -o $@ $(BASELIB_CXXFLAGS) $(srcdir)/src/msw/uilocale.cpp + baselib_core_mimetype.o: $(srcdir)/src/osx/core/mimetype.cpp $(BASELIB_ODEP) $(CXXC) -c -o $@ $(BASELIB_CXXFLAGS) $(srcdir)/src/osx/core/mimetype.cpp @@ -27115,6 +27188,9 @@ baselib_utils_base.o: $(srcdir)/src/osx/cocoa/utils_base.mm $(BASELIB_ODEP) baselib_core_secretstore.o: $(srcdir)/src/osx/core/secretstore.cpp $(BASELIB_ODEP) $(CXXC) -c -o $@ $(BASELIB_CXXFLAGS) $(srcdir)/src/osx/core/secretstore.cpp +baselib_core_uilocale.o: $(srcdir)/src/osx/core/uilocale.cpp $(BASELIB_ODEP) + $(CXXC) -c -o $@ $(BASELIB_CXXFLAGS) $(srcdir)/src/osx/core/uilocale.cpp + baselib_fswatcher_fsevents.o: $(srcdir)/src/osx/fswatcher_fsevents.cpp $(BASELIB_ODEP) $(CXXC) -c -o $@ $(BASELIB_CXXFLAGS) $(srcdir)/src/osx/fswatcher_fsevents.cpp diff --git a/build/bakefiles/files.bkl b/build/bakefiles/files.bkl index 32dca4cde8..afa23f0bcc 100644 --- a/build/bakefiles/files.bkl +++ b/build/bakefiles/files.bkl @@ -115,6 +115,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! src/unix/fswatcher_inotify.cpp src/unix/stdpaths.cpp src/unix/secretstore.cpp + src/unix/uilocale.cpp $(BASE_UNIX_AND_DARWIN_NOTWXMAC_HDR) @@ -146,6 +147,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! src/msw/utilsexc.cpp src/msw/fswatcher.cpp src/msw/secretstore.cpp + src/msw/uilocale.cpp src/msw/main.cpp @@ -187,6 +189,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! src/osx/core/strconv_cf.cpp src/osx/cocoa/utils_base.mm src/osx/core/secretstore.cpp + src/osx/core/uilocale.cpp wx/osx/core/cfdataref.h @@ -561,6 +564,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! src/generic/fswatcherg.cpp src/common/secretstore.cpp src/common/lzmastream.cpp + src/common/uilocale.cpp src/common/event.cpp @@ -736,6 +740,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! wx/secretstore.h wx/lzmastream.h wx/localedefs.h + wx/uilocale.h diff --git a/build/cmake/files.cmake b/build/cmake/files.cmake index 535259b3a5..df46473e51 100644 --- a/build/cmake/files.cmake +++ b/build/cmake/files.cmake @@ -47,6 +47,7 @@ set(BASE_UNIX_SRC src/unix/fswatcher_inotify.cpp src/unix/secretstore.cpp src/unix/stdpaths.cpp + src/unix/uilocale.cpp ) set(BASE_UNIX_HDR @@ -76,6 +77,7 @@ set(BASE_WIN32_SRC src/msw/utils.cpp src/msw/utilsexc.cpp src/msw/fswatcher.cpp + src/msw/uilocale.cpp ) set(BASE_AND_GUI_WIN32_SRC @@ -114,6 +116,7 @@ set(BASE_COREFOUNDATION_SRC src/osx/core/secretstore.cpp src/osx/core/strconv_cf.cpp src/osx/cocoa/utils_base.mm + src/osx/core/uilocale.cpp ) set(BASE_COREFOUNDATION_HDR @@ -475,6 +478,7 @@ set(BASE_CMN_SRC src/common/fswatchercmn.cpp src/generic/fswatcherg.cpp src/common/lzmastream.cpp + src/common/uilocale.cpp ) set(BASE_AND_GUI_CMN_SRC @@ -652,6 +656,7 @@ set(BASE_CMN_HDR wx/generic/fswatcher.h wx/lzmastream.h wx/localedefs.h + wx/uilocale.h ) set(NET_UNIX_SRC diff --git a/build/files b/build/files index 574cbb6e37..eafe03673d 100644 --- a/build/files +++ b/build/files @@ -71,6 +71,7 @@ BASE_UNIX_SRC = src/unix/fswatcher_inotify.cpp src/unix/secretstore.cpp src/unix/stdpaths.cpp + src/unix/uilocale.cpp BASE_UNIX_HDR = $(BASE_UNIX_AND_DARWIN_NOTWXMAC_HDR) @@ -98,6 +99,7 @@ BASE_WIN32_SRC = src/msw/stdpaths.cpp src/msw/thread.cpp src/msw/timer.cpp + src/msw/uilocale.cpp src/msw/utils.cpp src/msw/utilsexc.cpp src/msw/fswatcher.cpp @@ -139,6 +141,7 @@ BASE_COREFOUNDATION_SRC = src/osx/core/evtloop_cf.cpp src/osx/core/secretstore.cpp src/osx/core/strconv_cf.cpp + src/osx/core/uilocale.cpp src/osx/cocoa/utils_base.mm BASE_COREFOUNDATION_HDR = @@ -481,6 +484,7 @@ BASE_CMN_SRC = src/common/tokenzr.cpp src/common/translation.cpp src/common/txtstrm.cpp + src/common/uilocale.cpp src/common/unichar.cpp src/common/uri.cpp src/common/ustring.cpp @@ -633,6 +637,7 @@ BASE_CMN_HDR = wx/txtstrm.h wx/typeinfo.h wx/types.h + wx/uilocale.h wx/unichar.h wx/uri.h wx/ustring.h diff --git a/build/msw/makefile.gcc b/build/msw/makefile.gcc index 4ed7edba02..fcb8ae9aa3 100644 --- a/build/msw/makefile.gcc +++ b/build/msw/makefile.gcc @@ -477,6 +477,7 @@ MONODLL_OBJECTS = \ $(OBJS)\monodll_fswatcherg.o \ $(OBJS)\monodll_common_secretstore.o \ $(OBJS)\monodll_lzmastream.o \ + $(OBJS)\monodll_common_uilocale.o \ $(OBJS)\monodll_basemsw.o \ $(OBJS)\monodll_crashrpt.o \ $(OBJS)\monodll_debughlp.o \ @@ -497,6 +498,7 @@ MONODLL_OBJECTS = \ $(OBJS)\monodll_utilsexc.o \ $(OBJS)\monodll_fswatcher.o \ $(OBJS)\monodll_msw_secretstore.o \ + $(OBJS)\monodll_msw_uilocale.o \ $(OBJS)\monodll_event.o \ $(OBJS)\monodll_fs_mem.o \ $(OBJS)\monodll_msgout.o \ @@ -633,6 +635,7 @@ MONOLIB_OBJECTS = \ $(OBJS)\monolib_fswatcherg.o \ $(OBJS)\monolib_common_secretstore.o \ $(OBJS)\monolib_lzmastream.o \ + $(OBJS)\monolib_common_uilocale.o \ $(OBJS)\monolib_basemsw.o \ $(OBJS)\monolib_crashrpt.o \ $(OBJS)\monolib_debughlp.o \ @@ -653,6 +656,7 @@ MONOLIB_OBJECTS = \ $(OBJS)\monolib_utilsexc.o \ $(OBJS)\monolib_fswatcher.o \ $(OBJS)\monolib_msw_secretstore.o \ + $(OBJS)\monolib_msw_uilocale.o \ $(OBJS)\monolib_event.o \ $(OBJS)\monolib_fs_mem.o \ $(OBJS)\monolib_msgout.o \ @@ -783,6 +787,7 @@ BASEDLL_OBJECTS = \ $(OBJS)\basedll_fswatcherg.o \ $(OBJS)\basedll_common_secretstore.o \ $(OBJS)\basedll_lzmastream.o \ + $(OBJS)\basedll_common_uilocale.o \ $(OBJS)\basedll_basemsw.o \ $(OBJS)\basedll_crashrpt.o \ $(OBJS)\basedll_debughlp.o \ @@ -803,6 +808,7 @@ BASEDLL_OBJECTS = \ $(OBJS)\basedll_utilsexc.o \ $(OBJS)\basedll_fswatcher.o \ $(OBJS)\basedll_msw_secretstore.o \ + $(OBJS)\basedll_msw_uilocale.o \ $(OBJS)\basedll_event.o \ $(OBJS)\basedll_fs_mem.o \ $(OBJS)\basedll_msgout.o \ @@ -914,6 +920,7 @@ BASELIB_OBJECTS = \ $(OBJS)\baselib_fswatcherg.o \ $(OBJS)\baselib_common_secretstore.o \ $(OBJS)\baselib_lzmastream.o \ + $(OBJS)\baselib_common_uilocale.o \ $(OBJS)\baselib_basemsw.o \ $(OBJS)\baselib_crashrpt.o \ $(OBJS)\baselib_debughlp.o \ @@ -934,6 +941,7 @@ BASELIB_OBJECTS = \ $(OBJS)\baselib_utilsexc.o \ $(OBJS)\baselib_fswatcher.o \ $(OBJS)\baselib_msw_secretstore.o \ + $(OBJS)\baselib_msw_uilocale.o \ $(OBJS)\baselib_event.o \ $(OBJS)\baselib_fs_mem.o \ $(OBJS)\baselib_msgout.o \ @@ -7144,6 +7152,9 @@ $(OBJS)\monodll_common_secretstore.o: ../../src/common/secretstore.cpp $(OBJS)\monodll_lzmastream.o: ../../src/common/lzmastream.cpp $(CXX) -c -o $@ $(MONODLL_CXXFLAGS) $(CPPDEPS) $< +$(OBJS)\monodll_common_uilocale.o: ../../src/common/uilocale.cpp + $(CXX) -c -o $@ $(MONODLL_CXXFLAGS) $(CPPDEPS) $< + $(OBJS)\monodll_basemsw.o: ../../src/msw/basemsw.cpp $(CXX) -c -o $@ $(MONODLL_CXXFLAGS) $(CPPDEPS) $< @@ -7204,6 +7215,9 @@ $(OBJS)\monodll_fswatcher.o: ../../src/msw/fswatcher.cpp $(OBJS)\monodll_msw_secretstore.o: ../../src/msw/secretstore.cpp $(CXX) -c -o $@ $(MONODLL_CXXFLAGS) $(CPPDEPS) $< +$(OBJS)\monodll_msw_uilocale.o: ../../src/msw/uilocale.cpp + $(CXX) -c -o $@ $(MONODLL_CXXFLAGS) $(CPPDEPS) $< + $(OBJS)\monodll_event.o: ../../src/common/event.cpp $(CXX) -c -o $@ $(MONODLL_CXXFLAGS) $(CPPDEPS) $< @@ -9712,6 +9726,9 @@ $(OBJS)\monolib_common_secretstore.o: ../../src/common/secretstore.cpp $(OBJS)\monolib_lzmastream.o: ../../src/common/lzmastream.cpp $(CXX) -c -o $@ $(MONOLIB_CXXFLAGS) $(CPPDEPS) $< +$(OBJS)\monolib_common_uilocale.o: ../../src/common/uilocale.cpp + $(CXX) -c -o $@ $(MONOLIB_CXXFLAGS) $(CPPDEPS) $< + $(OBJS)\monolib_basemsw.o: ../../src/msw/basemsw.cpp $(CXX) -c -o $@ $(MONOLIB_CXXFLAGS) $(CPPDEPS) $< @@ -9772,6 +9789,9 @@ $(OBJS)\monolib_fswatcher.o: ../../src/msw/fswatcher.cpp $(OBJS)\monolib_msw_secretstore.o: ../../src/msw/secretstore.cpp $(CXX) -c -o $@ $(MONOLIB_CXXFLAGS) $(CPPDEPS) $< +$(OBJS)\monolib_msw_uilocale.o: ../../src/msw/uilocale.cpp + $(CXX) -c -o $@ $(MONOLIB_CXXFLAGS) $(CPPDEPS) $< + $(OBJS)\monolib_event.o: ../../src/common/event.cpp $(CXX) -c -o $@ $(MONOLIB_CXXFLAGS) $(CPPDEPS) $< @@ -12280,6 +12300,9 @@ $(OBJS)\basedll_common_secretstore.o: ../../src/common/secretstore.cpp $(OBJS)\basedll_lzmastream.o: ../../src/common/lzmastream.cpp $(CXX) -c -o $@ $(BASEDLL_CXXFLAGS) $(CPPDEPS) $< +$(OBJS)\basedll_common_uilocale.o: ../../src/common/uilocale.cpp + $(CXX) -c -o $@ $(BASEDLL_CXXFLAGS) $(CPPDEPS) $< + $(OBJS)\basedll_basemsw.o: ../../src/msw/basemsw.cpp $(CXX) -c -o $@ $(BASEDLL_CXXFLAGS) $(CPPDEPS) $< @@ -12340,6 +12363,9 @@ $(OBJS)\basedll_fswatcher.o: ../../src/msw/fswatcher.cpp $(OBJS)\basedll_msw_secretstore.o: ../../src/msw/secretstore.cpp $(CXX) -c -o $@ $(BASEDLL_CXXFLAGS) $(CPPDEPS) $< +$(OBJS)\basedll_msw_uilocale.o: ../../src/msw/uilocale.cpp + $(CXX) -c -o $@ $(BASEDLL_CXXFLAGS) $(CPPDEPS) $< + $(OBJS)\basedll_event.o: ../../src/common/event.cpp $(CXX) -c -o $@ $(BASEDLL_CXXFLAGS) $(CPPDEPS) $< @@ -12625,6 +12651,9 @@ $(OBJS)\baselib_common_secretstore.o: ../../src/common/secretstore.cpp $(OBJS)\baselib_lzmastream.o: ../../src/common/lzmastream.cpp $(CXX) -c -o $@ $(BASELIB_CXXFLAGS) $(CPPDEPS) $< +$(OBJS)\baselib_common_uilocale.o: ../../src/common/uilocale.cpp + $(CXX) -c -o $@ $(BASELIB_CXXFLAGS) $(CPPDEPS) $< + $(OBJS)\baselib_basemsw.o: ../../src/msw/basemsw.cpp $(CXX) -c -o $@ $(BASELIB_CXXFLAGS) $(CPPDEPS) $< @@ -12685,6 +12714,9 @@ $(OBJS)\baselib_fswatcher.o: ../../src/msw/fswatcher.cpp $(OBJS)\baselib_msw_secretstore.o: ../../src/msw/secretstore.cpp $(CXX) -c -o $@ $(BASELIB_CXXFLAGS) $(CPPDEPS) $< +$(OBJS)\baselib_msw_uilocale.o: ../../src/msw/uilocale.cpp + $(CXX) -c -o $@ $(BASELIB_CXXFLAGS) $(CPPDEPS) $< + $(OBJS)\baselib_event.o: ../../src/common/event.cpp $(CXX) -c -o $@ $(BASELIB_CXXFLAGS) $(CPPDEPS) $< diff --git a/build/msw/makefile.vc b/build/msw/makefile.vc index d8557a9f40..42d2c0634e 100644 --- a/build/msw/makefile.vc +++ b/build/msw/makefile.vc @@ -510,6 +510,7 @@ MONODLL_OBJECTS = \ $(OBJS)\monodll_fswatcherg.obj \ $(OBJS)\monodll_common_secretstore.obj \ $(OBJS)\monodll_lzmastream.obj \ + $(OBJS)\monodll_common_uilocale.obj \ $(OBJS)\monodll_basemsw.obj \ $(OBJS)\monodll_crashrpt.obj \ $(OBJS)\monodll_debughlp.obj \ @@ -530,6 +531,7 @@ MONODLL_OBJECTS = \ $(OBJS)\monodll_utilsexc.obj \ $(OBJS)\monodll_fswatcher.obj \ $(OBJS)\monodll_msw_secretstore.obj \ + $(OBJS)\monodll_msw_uilocale.obj \ $(OBJS)\monodll_event.obj \ $(OBJS)\monodll_fs_mem.obj \ $(OBJS)\monodll_msgout.obj \ @@ -675,6 +677,7 @@ MONOLIB_OBJECTS = \ $(OBJS)\monolib_fswatcherg.obj \ $(OBJS)\monolib_common_secretstore.obj \ $(OBJS)\monolib_lzmastream.obj \ + $(OBJS)\monolib_common_uilocale.obj \ $(OBJS)\monolib_basemsw.obj \ $(OBJS)\monolib_crashrpt.obj \ $(OBJS)\monolib_debughlp.obj \ @@ -695,6 +698,7 @@ MONOLIB_OBJECTS = \ $(OBJS)\monolib_utilsexc.obj \ $(OBJS)\monolib_fswatcher.obj \ $(OBJS)\monolib_msw_secretstore.obj \ + $(OBJS)\monolib_msw_uilocale.obj \ $(OBJS)\monolib_event.obj \ $(OBJS)\monolib_fs_mem.obj \ $(OBJS)\monolib_msgout.obj \ @@ -834,6 +838,7 @@ BASEDLL_OBJECTS = \ $(OBJS)\basedll_fswatcherg.obj \ $(OBJS)\basedll_common_secretstore.obj \ $(OBJS)\basedll_lzmastream.obj \ + $(OBJS)\basedll_common_uilocale.obj \ $(OBJS)\basedll_basemsw.obj \ $(OBJS)\basedll_crashrpt.obj \ $(OBJS)\basedll_debughlp.obj \ @@ -854,6 +859,7 @@ BASEDLL_OBJECTS = \ $(OBJS)\basedll_utilsexc.obj \ $(OBJS)\basedll_fswatcher.obj \ $(OBJS)\basedll_msw_secretstore.obj \ + $(OBJS)\basedll_msw_uilocale.obj \ $(OBJS)\basedll_event.obj \ $(OBJS)\basedll_fs_mem.obj \ $(OBJS)\basedll_msgout.obj \ @@ -977,6 +983,7 @@ BASELIB_OBJECTS = \ $(OBJS)\baselib_fswatcherg.obj \ $(OBJS)\baselib_common_secretstore.obj \ $(OBJS)\baselib_lzmastream.obj \ + $(OBJS)\baselib_common_uilocale.obj \ $(OBJS)\baselib_basemsw.obj \ $(OBJS)\baselib_crashrpt.obj \ $(OBJS)\baselib_debughlp.obj \ @@ -997,6 +1004,7 @@ BASELIB_OBJECTS = \ $(OBJS)\baselib_utilsexc.obj \ $(OBJS)\baselib_fswatcher.obj \ $(OBJS)\baselib_msw_secretstore.obj \ + $(OBJS)\baselib_msw_uilocale.obj \ $(OBJS)\baselib_event.obj \ $(OBJS)\baselib_fs_mem.obj \ $(OBJS)\baselib_msgout.obj \ @@ -7575,6 +7583,9 @@ $(OBJS)\monodll_common_secretstore.obj: ..\..\src\common\secretstore.cpp $(OBJS)\monodll_lzmastream.obj: ..\..\src\common\lzmastream.cpp $(CXX) /c /nologo /TP /Fo$@ $(MONODLL_CXXFLAGS) ..\..\src\common\lzmastream.cpp +$(OBJS)\monodll_common_uilocale.obj: ..\..\src\common\uilocale.cpp + $(CXX) /c /nologo /TP /Fo$@ $(MONODLL_CXXFLAGS) ..\..\src\common\uilocale.cpp + $(OBJS)\monodll_basemsw.obj: ..\..\src\msw\basemsw.cpp $(CXX) /c /nologo /TP /Fo$@ $(MONODLL_CXXFLAGS) ..\..\src\msw\basemsw.cpp @@ -7635,6 +7646,9 @@ $(OBJS)\monodll_fswatcher.obj: ..\..\src\msw\fswatcher.cpp $(OBJS)\monodll_msw_secretstore.obj: ..\..\src\msw\secretstore.cpp $(CXX) /c /nologo /TP /Fo$@ $(MONODLL_CXXFLAGS) ..\..\src\msw\secretstore.cpp +$(OBJS)\monodll_msw_uilocale.obj: ..\..\src\msw\uilocale.cpp + $(CXX) /c /nologo /TP /Fo$@ $(MONODLL_CXXFLAGS) ..\..\src\msw\uilocale.cpp + $(OBJS)\monodll_event.obj: ..\..\src\common\event.cpp $(CXX) /c /nologo /TP /Fo$@ $(MONODLL_CXXFLAGS) ..\..\src\common\event.cpp @@ -10143,6 +10157,9 @@ $(OBJS)\monolib_common_secretstore.obj: ..\..\src\common\secretstore.cpp $(OBJS)\monolib_lzmastream.obj: ..\..\src\common\lzmastream.cpp $(CXX) /c /nologo /TP /Fo$@ $(MONOLIB_CXXFLAGS) ..\..\src\common\lzmastream.cpp +$(OBJS)\monolib_common_uilocale.obj: ..\..\src\common\uilocale.cpp + $(CXX) /c /nologo /TP /Fo$@ $(MONOLIB_CXXFLAGS) ..\..\src\common\uilocale.cpp + $(OBJS)\monolib_basemsw.obj: ..\..\src\msw\basemsw.cpp $(CXX) /c /nologo /TP /Fo$@ $(MONOLIB_CXXFLAGS) ..\..\src\msw\basemsw.cpp @@ -10203,6 +10220,9 @@ $(OBJS)\monolib_fswatcher.obj: ..\..\src\msw\fswatcher.cpp $(OBJS)\monolib_msw_secretstore.obj: ..\..\src\msw\secretstore.cpp $(CXX) /c /nologo /TP /Fo$@ $(MONOLIB_CXXFLAGS) ..\..\src\msw\secretstore.cpp +$(OBJS)\monolib_msw_uilocale.obj: ..\..\src\msw\uilocale.cpp + $(CXX) /c /nologo /TP /Fo$@ $(MONOLIB_CXXFLAGS) ..\..\src\msw\uilocale.cpp + $(OBJS)\monolib_event.obj: ..\..\src\common\event.cpp $(CXX) /c /nologo /TP /Fo$@ $(MONOLIB_CXXFLAGS) ..\..\src\common\event.cpp @@ -12711,6 +12731,9 @@ $(OBJS)\basedll_common_secretstore.obj: ..\..\src\common\secretstore.cpp $(OBJS)\basedll_lzmastream.obj: ..\..\src\common\lzmastream.cpp $(CXX) /c /nologo /TP /Fo$@ $(BASEDLL_CXXFLAGS) ..\..\src\common\lzmastream.cpp +$(OBJS)\basedll_common_uilocale.obj: ..\..\src\common\uilocale.cpp + $(CXX) /c /nologo /TP /Fo$@ $(BASEDLL_CXXFLAGS) ..\..\src\common\uilocale.cpp + $(OBJS)\basedll_basemsw.obj: ..\..\src\msw\basemsw.cpp $(CXX) /c /nologo /TP /Fo$@ $(BASEDLL_CXXFLAGS) ..\..\src\msw\basemsw.cpp @@ -12771,6 +12794,9 @@ $(OBJS)\basedll_fswatcher.obj: ..\..\src\msw\fswatcher.cpp $(OBJS)\basedll_msw_secretstore.obj: ..\..\src\msw\secretstore.cpp $(CXX) /c /nologo /TP /Fo$@ $(BASEDLL_CXXFLAGS) ..\..\src\msw\secretstore.cpp +$(OBJS)\basedll_msw_uilocale.obj: ..\..\src\msw\uilocale.cpp + $(CXX) /c /nologo /TP /Fo$@ $(BASEDLL_CXXFLAGS) ..\..\src\msw\uilocale.cpp + $(OBJS)\basedll_event.obj: ..\..\src\common\event.cpp $(CXX) /c /nologo /TP /Fo$@ $(BASEDLL_CXXFLAGS) ..\..\src\common\event.cpp @@ -13056,6 +13082,9 @@ $(OBJS)\baselib_common_secretstore.obj: ..\..\src\common\secretstore.cpp $(OBJS)\baselib_lzmastream.obj: ..\..\src\common\lzmastream.cpp $(CXX) /c /nologo /TP /Fo$@ $(BASELIB_CXXFLAGS) ..\..\src\common\lzmastream.cpp +$(OBJS)\baselib_common_uilocale.obj: ..\..\src\common\uilocale.cpp + $(CXX) /c /nologo /TP /Fo$@ $(BASELIB_CXXFLAGS) ..\..\src\common\uilocale.cpp + $(OBJS)\baselib_basemsw.obj: ..\..\src\msw\basemsw.cpp $(CXX) /c /nologo /TP /Fo$@ $(BASELIB_CXXFLAGS) ..\..\src\msw\basemsw.cpp @@ -13116,6 +13145,9 @@ $(OBJS)\baselib_fswatcher.obj: ..\..\src\msw\fswatcher.cpp $(OBJS)\baselib_msw_secretstore.obj: ..\..\src\msw\secretstore.cpp $(CXX) /c /nologo /TP /Fo$@ $(BASELIB_CXXFLAGS) ..\..\src\msw\secretstore.cpp +$(OBJS)\baselib_msw_uilocale.obj: ..\..\src\msw\uilocale.cpp + $(CXX) /c /nologo /TP /Fo$@ $(BASELIB_CXXFLAGS) ..\..\src\msw\uilocale.cpp + $(OBJS)\baselib_event.obj: ..\..\src\common\event.cpp $(CXX) /c /nologo /TP /Fo$@ $(BASELIB_CXXFLAGS) ..\..\src\common\event.cpp diff --git a/build/msw/wx_base.vcxproj b/build/msw/wx_base.vcxproj index 8f8c9ae262..16a1d225c1 100644 --- a/build/msw/wx_base.vcxproj +++ b/build/msw/wx_base.vcxproj @@ -605,6 +605,26 @@ $(IntDir)common_%(Filename).obj + + $(IntDir)msw_%(Filename).obj + $(IntDir)msw_%(Filename).obj + $(IntDir)msw_%(Filename).obj + $(IntDir)msw_%(Filename).obj + $(IntDir)msw_%(Filename).obj + $(IntDir)msw_%(Filename).obj + $(IntDir)msw_%(Filename).obj + $(IntDir)msw_%(Filename).obj + + + $(IntDir)common_%(Filename).obj + $(IntDir)common_%(Filename).obj + $(IntDir)common_%(Filename).obj + $(IntDir)common_%(Filename).obj + $(IntDir)common_%(Filename).obj + $(IntDir)common_%(Filename).obj + $(IntDir)common_%(Filename).obj + $(IntDir)common_%(Filename).obj + @@ -824,6 +844,7 @@ + diff --git a/build/msw/wx_base.vcxproj.filters b/build/msw/wx_base.vcxproj.filters index 4c57355ba1..33a96e5ef0 100644 --- a/build/msw/wx_base.vcxproj.filters +++ b/build/msw/wx_base.vcxproj.filters @@ -261,6 +261,9 @@ Common Sources + + Common Sources + Common Sources @@ -360,6 +363,9 @@ MSW Sources + + MSW Sources + MSW Sources @@ -862,6 +868,9 @@ Common Headers + + Common Headers + Common Headers diff --git a/build/msw/wx_vc8_base.vcproj b/build/msw/wx_vc8_base.vcproj index 69963dce91..feb02ea5e3 100644 --- a/build/msw/wx_vc8_base.vcproj +++ b/build/msw/wx_vc8_base.vcproj @@ -1249,6 +1249,74 @@ RelativePath="..\..\src\common\txtstrm.cpp" > + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1446,6 +1514,74 @@ RelativePath="..\..\src\msw\timer.cpp" > + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2347,6 +2483,10 @@ RelativePath="..\..\include\wx\types.h" > + + diff --git a/build/msw/wx_vc9_base.vcproj b/build/msw/wx_vc9_base.vcproj index 1776e4de02..33df8ce65f 100644 --- a/build/msw/wx_vc9_base.vcproj +++ b/build/msw/wx_vc9_base.vcproj @@ -1245,6 +1245,74 @@ RelativePath="..\..\src\common\txtstrm.cpp" > + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1442,6 +1510,74 @@ RelativePath="..\..\src\msw\timer.cpp" > + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2343,6 +2479,10 @@ RelativePath="..\..\include\wx\types.h" > + + diff --git a/include/wx/intl.h b/include/wx/intl.h index b5c3458d6c..ab871ea6aa 100644 --- a/include/wx/intl.h +++ b/include/wx/intl.h @@ -90,6 +90,8 @@ enum wxLocaleInitFlags #endif }; +// NOTE: This class is deprecated, use wxUILocale and wxTranslations instead. + class WXDLLIMPEXP_BASE wxLocale { public: diff --git a/include/wx/private/uilocale.h b/include/wx/private/uilocale.h new file mode 100644 index 0000000000..89ce17a63c --- /dev/null +++ b/include/wx/private/uilocale.h @@ -0,0 +1,43 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/private/uilocale.h +// Purpose: wxUILocaleImpl class declaration +// Author: Vadim Zeitlin +// Created: 2021-08-01 +// Copyright: (c) 2021 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_PRIVATE_UILOCALE_H_ +#define _WX_PRIVATE_UILOCALE_H_ + +#include "wx/localedefs.h" +#include "wx/string.h" + +// ---------------------------------------------------------------------------- +// wxUILocaleImpl provides the implementation of public wxUILocale functions +// ---------------------------------------------------------------------------- + +class wxUILocaleImpl +{ +public: + // This function is implemented in platform-specific code and returns the + // object used by default, i.e. if wxUILocale::UseDefault() is not called. + // This object corresponds to the traditional "C" locale. + // + // It should never return NULL. + static wxUILocaleImpl* CreateStdC(); + + // Similarly, this one returns the object corresponding to the default user + // locale settings which is used if wxUILocale::UseDefault() was called. + // + // It may return NULL in case of failure. + static wxUILocaleImpl* CreateUserDefault(); + + // Functions corresponding to wxUILocale ones. + virtual wxString GetName() const = 0; + virtual wxString GetInfo(wxLocaleInfo index, wxLocaleCategory cat) const = 0; + + virtual ~wxUILocaleImpl() { } +}; + +#endif // _WX_PRIVATE_UILOCALE_H_ diff --git a/include/wx/uilocale.h b/include/wx/uilocale.h new file mode 100644 index 0000000000..f3aa9a2bb3 --- /dev/null +++ b/include/wx/uilocale.h @@ -0,0 +1,66 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/uilocale.h +// Purpose: wxUILocale class declaration. +// Author: Vadim Zeitlin +// Created: 2021-07-31 +// Copyright: (c) 2021 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_UILOCALE_H_ +#define _WX_UILOCALE_H_ + +#include "wx/defs.h" + +#if wxUSE_INTL + +#include "wx/localedefs.h" +#include "wx/string.h" + +class wxUILocaleImpl; + +// ---------------------------------------------------------------------------- +// wxUILocale allows to use the default UI locale and get information about it +// ---------------------------------------------------------------------------- + +class WXDLLIMPEXP_BASE wxUILocale +{ +public: + // Configure the UI to use the default user locale. + static bool UseDefault(); + + // Get the object corresponding to the currently used locale. + static const wxUILocale& GetCurrent(); + + // Get the platform-dependent name of the current locale. + wxString GetName() const; + + // Query the locale for the specified information. + wxString GetInfo(wxLocaleInfo index, + wxLocaleCategory cat = wxLOCALE_CAT_DEFAULT) const; + + // Note that this class is not supposed to be used polymorphically, hence + // its dtor is not virtual. + ~wxUILocale(); + +private: + // Ctor is private, use static accessor to get objects of this class. + wxUILocale() : m_impl(NULL) { } + + // Used by UseDefault(). + // + // Note that this object takes ownership of the provided pointer and will + // delete it in dtor. + void SetImpl(wxUILocaleImpl* impl); + + + static wxUILocale ms_current; + + wxUILocaleImpl* m_impl; + + wxDECLARE_NO_COPY_CLASS(wxUILocale); +}; + +#endif // wxUSE_INTL + +#endif // _WX_UILOCALE_H_ diff --git a/interface/wx/intl.h b/interface/wx/intl.h index 7cd5ab6964..92d1bab62d 100644 --- a/interface/wx/intl.h +++ b/interface/wx/intl.h @@ -69,7 +69,7 @@ struct wxLanguageInfo /** The category of locale settings. - @see wxLocale::GetInfo() + @see wxLocale::GetInfo(), wxUILocale::GetInfo() */ enum wxLocaleCategory { @@ -108,6 +108,8 @@ enum wxLocaleCategory All of these values are used with @c wxLOCALE_CAT_DATE in wxLocale::GetInfo() or, more typically, with @c wxLOCALE_CAT_DEFAULT as they only apply to a single category. + + @see wxUILocale::GetInfo() */ enum wxLocaleInfo { @@ -172,6 +174,13 @@ enum wxLocaleInfo wxLocale class encapsulates all language-dependent settings and is a generalization of the C locale concept. + @note While this class can still be used in wxMSW and wxGTK ports, it + doesn't work in wxOSX where it is impossible to change the application + UI locale after launching it. Worse, since macOS 11 (Big Sur), using + wxLocale can break application display due to bugs in C locale support + in macOS itself. Because of this, it is recommended to use wxUILocale + instead of this class for the applications targeting macOS. + In wxWidgets this class manages current locale. It also initializes and activates wxTranslations object that manages message catalogs. @@ -441,6 +450,9 @@ public: /** Get the values of a locale datum in the OS locale. + This function shouldn't be used in the new code, use + wxUILocale::GetInfo() instead. + This function is similar to GetInfo() and, in fact, identical to it under non-MSW systems. Under MSW it differs from it when no locale had been explicitly set: GetInfo() returns the values corresponding to the diff --git a/interface/wx/uilocale.h b/interface/wx/uilocale.h new file mode 100644 index 0000000000..d31eaf1b89 --- /dev/null +++ b/interface/wx/uilocale.h @@ -0,0 +1,106 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/uilocale.h +// Purpose: Interface of wxUILocale +// Author: Vadim Zeitlin +// Created: 2021-08-01 +// Copyright: (c) 2021 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +/** + Query and modify locale used for the UI by the current platform. + + UI locale determines all culture-dependent conventions used in the user + interface, including numbers, currencies and dates formatting. It also + determines the language used by the native dialogs, such as wxFileDialog, + where different labels use the language corresponding to the current UI + locale. + + The UI locale is, in general, different from C locale set by the standard + @c setlocale() function and affecting C standard library functions such as + @c printf(), @c scanf(), @c strftime() and many others. Unfortunately, the + relationship between C and UI locales is not the same depending on the + platform: with wxGTK they must be the same, but under macOS C locale must + not be changed, as doing this exposes bugs in the system. Because of this, + applications can't generally count on C locale being set to any particular + value and it is best to avoid using it, including implicitly via the + standard C functions, in portable code. Instead, consider using + wxNumberFormatter for parsing and formatting numbers according to the + current UI locale or wxString::FromCDouble() and wxString::ToCDouble() + functions for doing it always using period as decimal separator. + + Localized applications should call wxUILocale::UseDefault() on startup to + explicitly indicate that they opt-in using the current UI locale, even if + this results in changing the global C locale, as is the case in wxGTK. Note + that some platforms (MSW and macOS) will use default user locale for their + standard dialogs even if this function is not called, but it is still + necessary to call it to use the correct number and date formats and to + avoid mixing messages in the user language with default formats not + corresponding to it. + + Please also note that under macOS to really use the user locale, it must be + listed as a supported language in the application @c Info.plist file under + @c CFBundleLocalizations key. + + Unlike wxLocale class, this class doesn't affect the translations used by + the application, see wxTranslations for doing this. + + @library{wxbase} + @since 3.1.6 + */ +class wxUILocale +{ +public: + /** + Configure the UI to use the default user locale. + + Localized applications should call this functions as early as possible + during the program startup, e.g. in the very beginning of the + overridden wxApp::OnInit(). + + Note that under most Unix systems (but not macOS) this function changes + the C locale to the locale specified by the environment variables and + so affects the results of calling C functions such as @c sprintf() etc + which can use comma, rather than period, as decimal separator. The + wxString::ToCDouble() and wxString::FromCDouble() functions can be used + for parsing and formatting floating point numbers using period as + decimal separator independently of the current locale. + + @return @true on success or @false if the default locale couldn't be set + */ + static bool UseDefault(); + + /** + Get the object corresponding to the currently used locale. + + If UseDefault() had been called, this object corresponds to the default + user locale. Otherwise it corresponds to a generic locale similar to + "C" locale, i.e. always uses period as decimal separator and m/d/y date + format. + */ + static const wxUILocale& GetCurrent(); + + /** + Get the platform-dependent name of the current locale. + + This name can be used in diagnostic messages. + */ + wxString GetName() const; + + /** + Query the locale for the specified information. + + This function returns the value of the locale-specific option specified + by the given @a index. + + @param index + One of the elements of wxLocaleInfo enum. + @param cat + The category to use with the given index or wxLOCALE_CAT_DEFAULT if + the index can only apply to a single category. + @return + The option value or empty string if the function failed. + */ + wxString GetInfo(wxLocaleInfo index, + wxLocaleCategory cat = wxLOCALE_CAT_DEFAULT) const; +}; diff --git a/samples/internat/internat.cpp b/samples/internat/internat.cpp index 21abd20e1c..2bd0af7af0 100644 --- a/samples/internat/internat.cpp +++ b/samples/internat/internat.cpp @@ -37,6 +37,7 @@ #include "wx/platinfo.h" #include "wx/spinctrl.h" #include "wx/translation.h" +#include "wx/uilocale.h" #ifndef wxHAS_IMAGES_IN_RESOURCES #include "../sample.xpm" @@ -73,15 +74,13 @@ protected: Locale_Set, Locale_Skip } m_setLocale; - - wxLocale m_locale; // locale we'll be using }; // Define a new frame type class MyFrame: public wxFrame { public: - MyFrame(wxLocale& m_locale); + MyFrame(); public: void OnTestLocaleAvail(wxCommandEvent& event); @@ -228,9 +227,7 @@ bool MyApp::OnInit() if ( m_setLocale == Locale_Set ) { - // don't use wxLOCALE_LOAD_DEFAULT flag so that Init() doesn't return - // false just because it failed to load wxstd catalog - if ( !m_locale.Init(wxLANGUAGE_DEFAULT, wxLOCALE_DONT_LOAD_DEFAULT) ) + if ( !wxUILocale::UseDefault() ) { wxLogWarning("Failed to initialize the default system locale."); } @@ -272,7 +269,7 @@ bool MyApp::OnInit() } // Create the main frame window - MyFrame *frame = new MyFrame(m_locale); + MyFrame *frame = new MyFrame(); // Show the frame frame->Show(true); @@ -285,7 +282,7 @@ bool MyApp::OnInit() // ---------------------------------------------------------------------------- // main frame constructor -MyFrame::MyFrame(wxLocale& locale) +MyFrame::MyFrame() : wxFrame(NULL, wxID_ANY, _("International wxWidgets App")) @@ -352,14 +349,18 @@ MyFrame::MyFrame(wxLocale& locale) wxSizer* const topSizer = new wxBoxSizer(wxVERTICAL); - wxString localeInfo; - wxString locale = locale.GetLocale(); - wxString sysname = locale.GetSysName(); - wxString canname = locale.GetCanonicalName(); - localeInfo.Printf("Current locale: %s (system name: %s, canonical name: %s)", - locale, sysname, canname ); - - topSizer->Add(new wxStaticText(panel, wxID_ANY, localeInfo), + // create controls showing the locale being used + topSizer->Add(new wxStaticText + ( + panel, + wxID_ANY, + wxString::Format + ( + _("Current UI locale: %s; C locale: %s"), + wxUILocale::GetCurrent().GetName(), + setlocale(LC_ALL, NULL) + ) + ), wxSizerFlags().Center().Border()); // create some controls affected by the locale diff --git a/src/common/intl.cpp b/src/common/intl.cpp index d9b166557d..c6c82186d2 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -1601,6 +1601,10 @@ wxString wxTranslateFromUnicodeFormat(const wxString& fmt) #if defined(__WINDOWS__) +// This function is also used by wxUILocaleImpl, so don't make it private. +extern wxString +wxGetInfoFromLCID(LCID lcid, wxLocaleInfo index, wxLocaleCategory cat); + namespace { @@ -1624,10 +1628,38 @@ LCTYPE GetLCTYPEFormatFromLocalInfo(wxLocaleInfo index) return 0; } +// This private function additionally checks consistency of the decimal +// separator settings between MSW and CRT. wxString -GetInfoFromLCID(LCID lcid, - wxLocaleInfo index, - wxLocaleCategory cat = wxLOCALE_CAT_DEFAULT) +GetInfoFromLCID(LCID lcid, wxLocaleInfo index, wxLocaleCategory cat) +{ + const wxString str = wxGetInfoFromLCID(lcid, index, cat); + + if ( !str.empty() && index == wxLOCALE_DECIMAL_POINT ) + { + // As we get our decimal point separator from Win32 and not the + // CRT there is a possibility of mismatch between them and this + // can easily happen if the user code called setlocale() + // instead of using wxLocale to change the locale. And this can + // result in very strange bugs elsewhere in the code as the + // assumptions that formatted strings do use the decimal + // separator actually fail, so check for it here. + wxASSERT_MSG + ( + wxString::Format("%.3f", 1.23).find(str) != wxString::npos, + "Decimal separator mismatch -- did you use setlocale()?" + "If so, use wxLocale to change the locale instead." + ); + } + + return str; +} + +} // anonymous namespace + +// This function is also used by wxUILocaleImpl, so don't make it private. +wxString +wxGetInfoFromLCID(LCID lcid, wxLocaleInfo index, wxLocaleCategory cat) { wxString str; @@ -1650,20 +1682,6 @@ GetInfoFromLCID(LCID lcid, WXSIZEOF(buf)) ) { str = buf; - - // As we get our decimal point separator from Win32 and not the - // CRT there is a possibility of mismatch between them and this - // can easily happen if the user code called setlocale() - // instead of using wxLocale to change the locale. And this can - // result in very strange bugs elsewhere in the code as the - // assumptions that formatted strings do use the decimal - // separator actually fail, so check for it here. - wxASSERT_MSG - ( - wxString::Format("%.3f", 1.23).find(str) != wxString::npos, - "Decimal separator mismatch -- did you use setlocale()?" - "If so, use wxLocale to change the locale instead." - ); } break; @@ -1686,12 +1704,12 @@ GetInfoFromLCID(LCID lcid, // alternate representation here) { const wxString - datefmt = GetInfoFromLCID(lcid, wxLOCALE_SHORT_DATE_FMT); + datefmt = wxGetInfoFromLCID(lcid, wxLOCALE_SHORT_DATE_FMT, cat); if ( datefmt.empty() ) break; const wxString - timefmt = GetInfoFromLCID(lcid, wxLOCALE_TIME_FMT); + timefmt = wxGetInfoFromLCID(lcid, wxLOCALE_TIME_FMT, cat); if ( timefmt.empty() ) break; @@ -1706,8 +1724,6 @@ GetInfoFromLCID(LCID lcid, return str; } -} // anonymous namespace - /* static */ wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory cat) { @@ -1766,34 +1782,19 @@ wxString wxLocale::GetOSInfo(wxLocaleInfo index, wxLocaleCategory cat) #elif defined(__WXOSX__) -/* static */ -wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory WXUNUSED(cat)) +// This function is also used by wxUILocaleImpl, so don't make it private. +extern wxString +wxGetInfoFromCFLocale(CFLocaleRef cfloc, wxLocaleInfo index, wxLocaleCategory WXUNUSED(cat)) { - CFLocaleRef userLocaleRefRaw; - if ( wxGetLocale() ) - { - userLocaleRefRaw = CFLocaleCreate - ( - kCFAllocatorDefault, - wxCFStringRef(wxGetLocale()->GetCanonicalName()) - ); - } - else // no current locale, use the default one - { - userLocaleRefRaw = CFLocaleCopyCurrent(); - } - - wxCFRef userLocaleRef(userLocaleRefRaw); - CFStringRef cfstr = 0; switch ( index ) { case wxLOCALE_THOUSANDS_SEP: - cfstr = (CFStringRef) CFLocaleGetValue(userLocaleRef, kCFLocaleGroupingSeparator); + cfstr = (CFStringRef) CFLocaleGetValue(cfloc, kCFLocaleGroupingSeparator); break; case wxLOCALE_DECIMAL_POINT: - cfstr = (CFStringRef) CFLocaleGetValue(userLocaleRef, kCFLocaleDecimalSeparator); + cfstr = (CFStringRef) CFLocaleGetValue(cfloc, kCFLocaleDecimalSeparator); break; case wxLOCALE_SHORT_DATE_FMT: @@ -1823,7 +1824,7 @@ wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory WXUNUSED(cat)) return wxString(); } wxCFRef dateFormatter( CFDateFormatterCreate - (NULL, userLocaleRef, dateStyle, timeStyle)); + (NULL, cfloc, dateStyle, timeStyle)); wxCFStringRef cfs = wxCFRetain( CFDateFormatterGetFormat(dateFormatter )); wxString format = wxTranslateFromUnicodeFormat(cfs.AsString()); // we always want full years @@ -1840,6 +1841,28 @@ wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory WXUNUSED(cat)) return str.AsString(); } +/* static */ +wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory cat) +{ + CFLocaleRef userLocaleRefRaw; + if ( wxGetLocale() ) + { + userLocaleRefRaw = CFLocaleCreate + ( + kCFAllocatorDefault, + wxCFStringRef(wxGetLocale()->GetCanonicalName()) + ); + } + else // no current locale, use the default one + { + userLocaleRefRaw = CFLocaleCopyCurrent(); + } + + wxCFRef userLocaleRef(userLocaleRefRaw); + + return wxGetInfoFromCFLocale(userLocaleRef, index, cat); +} + #else // !__WINDOWS__ && !__WXOSX__, assume generic POSIX namespace diff --git a/src/common/uilocale.cpp b/src/common/uilocale.cpp new file mode 100644 index 0000000000..bf79b77189 --- /dev/null +++ b/src/common/uilocale.cpp @@ -0,0 +1,90 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/uilocale.cpp +// Purpose: wxUILocale implementation +// Author: Vadim Zeitlin +// Created: 2021-07-31 +// Copyright: (c) 2021 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#if wxUSE_INTL + +#include "wx/uilocale.h" + +#include "wx/private/uilocale.h" + +// ---------------------------------------------------------------------------- +// global variables +// ---------------------------------------------------------------------------- + +// This static global variable doesn't need to be protected from concurrent +// access as it's only supposed to be used from the UI thread. +/* static */ +wxUILocale wxUILocale::ms_current; + +// ============================================================================ +// implementation +// ============================================================================ + +/* static */ +bool wxUILocale::UseDefault() +{ + // We don't attempt to optimize this function by checking whether + // ms_current is already set to the user default locale, as we're + // supposed to be called just once during the program lifetime anyhow. + + wxUILocaleImpl* const impl = wxUILocaleImpl::CreateUserDefault(); + if ( !impl ) + return false; + + ms_current.SetImpl(impl); + + return true; +} + +/* static */ +const wxUILocale& wxUILocale::GetCurrent() +{ + // We initialize it on demand. + if ( !ms_current.m_impl ) + { + ms_current.SetImpl(wxUILocaleImpl::CreateStdC()); + } + + return ms_current; +} + +void wxUILocale::SetImpl(wxUILocaleImpl* impl) +{ + delete m_impl; + + m_impl = impl; +} + +wxString wxUILocale::GetName() const +{ + return m_impl->GetName(); +} + +wxString wxUILocale::GetInfo(wxLocaleInfo index, wxLocaleCategory cat) const +{ + return m_impl->GetInfo(index, cat); +} + +wxUILocale::~wxUILocale() +{ + delete m_impl; +} + +#endif // wxUSE_INTL diff --git a/src/msw/uilocale.cpp b/src/msw/uilocale.cpp new file mode 100644 index 0000000000..21070de0c0 --- /dev/null +++ b/src/msw/uilocale.cpp @@ -0,0 +1,101 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: src/msw/uilocale.cpp +// Purpose: wxUILocale implementation for MSW +// Author: Vadim Zeitlin +// Created: 2021-07-31 +// Copyright: (c) 2021 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#if wxUSE_INTL + +#include "wx/private/uilocale.h" + +#include "wx/dynlib.h" + +#include "wx/msw/private.h" + +#ifndef LOCALE_SNAME +#define LOCALE_SNAME 0x5c +#endif + +// This function is defined in src/common/intl.cpp, just declare it here for +// now before refactoring the code. +wxString wxGetInfoFromLCID(LCID lcid, wxLocaleInfo index, wxLocaleCategory cat); + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxUILocale implementation for MSW +// ---------------------------------------------------------------------------- + +// TODO-XP: Replace this with an implementation using GetLocaleInfoEx() when we +// don't support XP any longer. +class wxUILocaleImplLCID : public wxUILocaleImpl +{ +public: + explicit wxUILocaleImplLCID(LCID lcid) + : m_lcid(lcid) + { + } + + wxString GetName() const wxOVERRIDE + { + wxChar buf[256]; + buf[0] = wxT('\0'); + + // Try using newer constant available since Vista which produces names + // more similar to the other platforms. + if ( wxGetWinVersion() >= wxWinVersion_Vista ) + { + ::GetLocaleInfo(m_lcid, LOCALE_SNAME, buf, WXSIZEOF(buf)); + } + else // TODO-XP: Drop this branch. + { + // This name constant is available under all systems, including + // pre-Vista ones. + ::GetLocaleInfo(m_lcid, LOCALE_SENGLANGUAGE, buf, WXSIZEOF(buf)); + } + + return buf; + } + + wxString GetInfo(wxLocaleInfo index, wxLocaleCategory cat) const wxOVERRIDE + { + return wxGetInfoFromLCID(m_lcid, index, cat); + } + +private: + const LCID m_lcid; + + wxDECLARE_NO_COPY_CLASS(wxUILocaleImplLCID); +}; + +/* static */ +wxUILocaleImpl* wxUILocaleImpl::CreateStdC() +{ + // There is no LCID for "C" locale, but US English is basically the same. + LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT); + return new wxUILocaleImplLCID(lcid); +} + +/* static */ +wxUILocaleImpl* wxUILocaleImpl::CreateUserDefault() +{ + return new wxUILocaleImplLCID(LOCALE_USER_DEFAULT); +} + +#endif // wxUSE_INTL diff --git a/src/osx/core/uilocale.cpp b/src/osx/core/uilocale.cpp new file mode 100644 index 0000000000..3309343739 --- /dev/null +++ b/src/osx/core/uilocale.cpp @@ -0,0 +1,92 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: src/osx/core/uilocale.cpp +// Purpose: wxUILocale implementation for macOS +// Author: Vadim Zeitlin +// Created: 2021-08-01 +// Copyright: (c) 2021 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#if wxUSE_INTL + +#include "wx/private/uilocale.h" + +#include "wx/osx/core/cfref.h" +#include "wx/osx/core/cfstring.h" + +#include +#include + +extern wxString +wxGetInfoFromCFLocale(CFLocaleRef cfloc, wxLocaleInfo index, wxLocaleCategory cat); + +namespace +{ + +// ---------------------------------------------------------------------------- +// wxUILocale implementation using Core Foundation +// ---------------------------------------------------------------------------- + +class wxUILocaleImplCF : public wxUILocaleImpl +{ +public: + explicit wxUILocaleImplCF(const wxCFRef& cfloc) + : m_cfloc(cfloc) + { + } + + wxString GetName() const wxOVERRIDE; + wxString GetInfo(wxLocaleInfo index, wxLocaleCategory cat) const wxOVERRIDE; + +private: + wxCFRef m_cfloc; + + wxDECLARE_NO_COPY_CLASS(wxUILocaleImplCF); +}; + +} // anonymous namespace + +// ============================================================================ +// implementation +// ============================================================================ + +wxString +wxUILocaleImplCF::GetName() const +{ + return wxCFStringRef::AsString(CFLocaleGetIdentifier(m_cfloc)); +} + +wxString +wxUILocaleImplCF::GetInfo(wxLocaleInfo index, wxLocaleCategory cat) const +{ + return wxGetInfoFromCFLocale(m_cfloc, index, cat); +} + +/* static */ +wxUILocaleImpl* wxUILocaleImpl::CreateStdC() +{ + CFLocaleRef cfloc = CFLocaleCreate(kCFAllocatorDefault, wxCFStringRef("C")); + if ( !cfloc ) + return NULL; + + return new wxUILocaleImplCF(cfloc); +} + +/* static */ +wxUILocaleImpl* wxUILocaleImpl::CreateUserDefault() +{ + return new wxUILocaleImplCF(CFLocaleCopyCurrent()); +} + +#endif // wxUSE_INTL diff --git a/src/unix/uilocale.cpp b/src/unix/uilocale.cpp new file mode 100644 index 0000000000..a817ad899d --- /dev/null +++ b/src/unix/uilocale.cpp @@ -0,0 +1,91 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: src/unix/uilocale.cpp +// Purpose: wxUILocale implementation for Unix systems +// Author: Vadim Zeitlin +// Created: 2021-08-01 +// Copyright: (c) 2021 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#if wxUSE_INTL + +#include "wx/private/uilocale.h" + +#include "wx/intl.h" + +#include + +namespace +{ + +// ---------------------------------------------------------------------------- +// wxUILocale implementation using standard Unix/C functions +// ---------------------------------------------------------------------------- + +class wxUILocaleImplUnix : public wxUILocaleImpl +{ +public: + // Locale argument may be NULL to not change it at all. + explicit wxUILocaleImplUnix(const char* locale); + + wxString GetName() const wxOVERRIDE; + wxString GetInfo(wxLocaleInfo index, wxLocaleCategory cat) const wxOVERRIDE; + +private: + wxDECLARE_NO_COPY_CLASS(wxUILocaleImplUnix); +}; + +} // anonymous namespace + +// ============================================================================ +// implementation +// ============================================================================ + +wxUILocaleImplUnix::wxUILocaleImplUnix(const char* locale) +{ + if ( locale ) + setlocale(LC_ALL, locale); +} + +wxString +wxUILocaleImplUnix::GetName() const +{ + return wxString::FromAscii(setlocale(LC_ALL, NULL)); +} + +wxString +wxUILocaleImplUnix::GetInfo(wxLocaleInfo index, wxLocaleCategory cat) const +{ + // Currently we rely on the user code not calling setlocale() itself, so + // that the current locale is still the same as was set in the ctor. + // + // If this assumption turns out to be wrong, we could use wxLocaleSetter to + // temporarily change the locale here (maybe only if setlocale(NULL) result + // differs from the expected one). + return wxLocale::GetInfo(index, cat); +} + +/* static */ +wxUILocaleImpl* wxUILocaleImpl::CreateStdC() +{ + return new wxUILocaleImplUnix(NULL); +} + +/* static */ +wxUILocaleImpl* wxUILocaleImpl::CreateUserDefault() +{ + return new wxUILocaleImplUnix(""); +} + +#endif // wxUSE_INTL diff --git a/tests/intl/intltest.cpp b/tests/intl/intltest.cpp index c19628b4c0..d6db0c8a56 100644 --- a/tests/intl/intltest.cpp +++ b/tests/intl/intltest.cpp @@ -18,6 +18,7 @@ #endif // WX_PRECOMP #include "wx/intl.h" +#include "wx/uilocale.h" #if wxUSE_INTL @@ -239,4 +240,17 @@ TEST_CASE("wxLocale::Default", "[locale]") #endif // wxUSE_UNICODE +// This test doesn't run by default as it only works in locales using decimal +// point as separator, which doesn't need to be the case. +TEST_CASE("wxUILocale::GetInfo", "[.][uilocale]") +{ + REQUIRE( wxUILocale::UseDefault() ); + + const wxUILocale& loc = wxUILocale::GetCurrent(); + + WARN( "Using locale " << loc.GetName() ); + + CHECK( loc.GetInfo(wxLOCALE_DECIMAL_POINT) == "." ); +} + #endif // wxUSE_INTL From 8f20dd34903fa575e137eca430f105001672d186 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 14 Aug 2021 17:12:33 +0100 Subject: [PATCH 15/28] Remove obsolete AIX workaround from wxLocale code This code, added back in 420de418ea (workaround for buggy setlocale() under AIX (without this wxLocale didn't work at all), 2005-09-18), is probably irrelevant anyhow because AIX 5.2 must not be used any more, but also seems to have lost its purpose at some time during the intervening years, as we don't use "retloc" as argument to setlocale() anyhow, so it is doubly safe to simply remove it. --- src/common/intl.cpp | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/common/intl.cpp b/src/common/intl.cpp index c6c82186d2..cc8588ba31 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -552,20 +552,6 @@ bool wxLocale::Init(int lang, int flags) if ( !localeAlt.empty() ) retloc = wxSetlocaleTryAll(LC_ALL, localeAlt); } - -#ifdef __AIX__ - // at least in AIX 5.2 libc is buggy and the string returned from - // setlocale(LC_ALL) can't be passed back to it because it returns 6 - // strings (one for each locale category), i.e. for C locale we get back - // "C C C C C C" - // - // this contradicts IBM own docs but this is not of much help, so just work - // around it in the crudest possible manner - char* p = const_cast(wxStrchr(retloc, ' ')); - if ( p ) - *p = '\0'; -#endif // __AIX__ - #elif defined(__WIN32__) if ( lang == wxLANGUAGE_DEFAULT ) { From 59a4505a5fe23083db169b0fb50c73c4d8836443 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 14 Aug 2021 19:06:14 +0200 Subject: [PATCH 16/28] Use Core Foundation for testing locale availability under Mac Using setlocale() is not the right way to do it there, try checking if the locale is supported by Core Foundation instead of whether it's supported by the Unix layer which is neglected and not used under Mac. --- src/common/intl.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/common/intl.cpp b/src/common/intl.cpp index cc8588ba31..4d900c45ad 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -1131,6 +1131,13 @@ bool wxLocale::IsAvailable(int lang) if ( !::IsValidLocale(info->GetLCID(), LCID_INSTALLED) ) return false; +#elif defined(__WXOSX__) + CFLocaleRef + cfloc = CFLocaleCreate(kCFAllocatorDefault, wxCFStringRef(info->CanonicalName)); + if ( !cfloc ) + return false; + + CFRelease(cfloc); #elif defined(__UNIX__) // Test if setting the locale works, then set it back. From 405bb3ecf7b29362ddf9a906bf820928765a7835 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 14 Aug 2021 17:41:08 +0100 Subject: [PATCH 17/28] Move wxLanguageInfo declaration to wx/localedefs.h too No real changes, just allow wxUILocale code to use this struct without including the full wx/intl.h. This commit is best viewed with --color-moved git option. --- include/wx/intl.h | 34 ---------------------------------- include/wx/localedefs.h | 38 +++++++++++++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 35 deletions(-) diff --git a/include/wx/intl.h b/include/wx/intl.h index ab871ea6aa..866bcfbcac 100644 --- a/include/wx/intl.h +++ b/include/wx/intl.h @@ -41,40 +41,6 @@ class WXDLLIMPEXP_FWD_BASE wxLanguageInfoArray; // locale support // ============================================================================ -// ---------------------------------------------------------------------------- -// wxLanguageInfo: encapsulates wxLanguage to OS native lang.desc. -// translation information -// ---------------------------------------------------------------------------- - -struct WXDLLIMPEXP_BASE wxLanguageInfo -{ - int Language; // wxLanguage id - wxString CanonicalName; // Canonical name, e.g. fr_FR -#ifdef __WINDOWS__ - wxUint32 WinLang, // Win32 language identifiers - WinSublang; -#endif // __WINDOWS__ - wxString Description; // human-readable name of the language - wxLayoutDirection LayoutDirection; - -#ifdef __WINDOWS__ - // return the LCID corresponding to this language - wxUint32 GetLCID() const; -#endif // __WINDOWS__ - - // return the locale name corresponding to this language usable with - // setlocale() on the current system or empty string if this locale is not - // supported - wxString GetLocaleName() const; - - // Call setlocale() and return non-null value if it works for this language. - // - // This function is mostly for internal use, as changing locale involves - // more than just calling setlocale() on some platforms, use wxLocale to - // do everything that needs to be done instead of calling this method. - const char* TrySetLocale() const; -}; - // ---------------------------------------------------------------------------- // wxLocale: encapsulates all language dependent settings, including current // message catalogs, date, time and currency formats (TODO) &c diff --git a/include/wx/localedefs.h b/include/wx/localedefs.h index 727c79bbd0..d5b43b2eff 100644 --- a/include/wx/localedefs.h +++ b/include/wx/localedefs.h @@ -1,6 +1,6 @@ /////////////////////////////////////////////////////////////////////////////// // Name: wx/localedefs.h -// Purpose: Definitions of common locale-related constants +// Purpose: Definitions of common locale-related constants and structs. // Author: Vadim Zeitlin // Created: 2021-07-31 (extracted from wx/intl.h) // Copyright: (c) 2021 Vadim Zeitlin @@ -26,6 +26,8 @@ enum wxLayoutDirection #if wxUSE_INTL +#include "wx/string.h" + // ---------------------------------------------------------------------------- // wxLocaleCategory: the category of locale settings // ---------------------------------------------------------------------------- @@ -72,6 +74,40 @@ enum wxLocaleInfo }; +// ---------------------------------------------------------------------------- +// wxLanguageInfo: encapsulates wxLanguage to OS native lang.desc. +// translation information +// ---------------------------------------------------------------------------- + +struct WXDLLIMPEXP_BASE wxLanguageInfo +{ + int Language; // wxLanguage id + wxString CanonicalName; // Canonical name, e.g. fr_FR +#ifdef __WINDOWS__ + wxUint32 WinLang, // Win32 language identifiers + WinSublang; +#endif // __WINDOWS__ + wxString Description; // human-readable name of the language + wxLayoutDirection LayoutDirection; + +#ifdef __WINDOWS__ + // return the LCID corresponding to this language + wxUint32 GetLCID() const; +#endif // __WINDOWS__ + + // return the locale name corresponding to this language usable with + // setlocale() on the current system or empty string if this locale is not + // supported + wxString GetLocaleName() const; + + // Call setlocale() and return non-null value if it works for this language. + // + // This function is mostly for internal use, as changing locale involves + // more than just calling setlocale() on some platforms, use wxLocale to + // do everything that needs to be done instead of calling this method. + const char* TrySetLocale() const; +}; + #endif // wxUSE_INTL #endif // _WX_LOCALEDEFS_H_ From d3a1abaab208e8ba05f250a6dac0e5fccc11a4be Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Fri, 20 Aug 2021 23:35:16 +0200 Subject: [PATCH 18/28] Untangle Mac and POSIX code in wxLocale::GetSystemLanguage() Most of the code in this function was Unix-specific and didn't make sense for Mac, where we never have to apply the workarounds in it nor deal with languages specified without the territory etc, so separate Mac branch using CoreFouundation API from the rest of the Unix code to make things more understandable. No real changes. --- src/common/intl.cpp | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/src/common/intl.cpp b/src/common/intl.cpp index 4d900c45ad..e0966452e3 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -634,9 +634,6 @@ inline bool wxGetNonEmptyEnvVar(const wxString& name, wxString* value) size_t i = 0, count = ms_languagesDB->GetCount(); -#if defined(__UNIX__) - // first get the string identifying the language from the environment - wxString langFull; #ifdef __WXOSX__ wxCFRef userLocaleRef(CFLocaleCopyCurrent()); @@ -644,10 +641,34 @@ inline bool wxGetNonEmptyEnvVar(const wxString& name, wxString* value) // az_Cyrl_AZ@calendar=buddhist;currency=JPY we just recreate the base info as expected by wx here wxCFStringRef str(wxCFRetain((CFStringRef)CFLocaleGetValue(userLocaleRef, kCFLocaleLanguageCode))); - langFull = str.AsString()+"_"; + const wxString langPrefix = str.AsString() + "_"; + str.reset(wxCFRetain((CFStringRef)CFLocaleGetValue(userLocaleRef, kCFLocaleCountryCode))); - langFull += str.AsString(); -#else + const wxString langFull = langPrefix + str.AsString(); + + int langOnlyMatchIndex = wxNOT_FOUND; + for ( i = 0; i < count; i++ ) + { + const wxString& fullname = ms_languagesDB->Item(i).CanonicalName; + if ( langFull == fullname ) + { + // Exact match, no need to look any further. + break; + } + + if ( fullname.StartsWith(langPrefix) ) + { + // Matched just the language, keep looking, but we'll keep this if + // we don't find an exact match later. + langOnlyMatchIndex = i; + } + } + + if ( i == count && langOnlyMatchIndex != wxNOT_FOUND ) + i = langOnlyMatchIndex; +#elif defined(__UNIX__) + // first get the string identifying the language from the environment + wxString langFull; if (!wxGetNonEmptyEnvVar(wxS("LC_ALL"), &langFull) && !wxGetNonEmptyEnvVar(wxS("LC_MESSAGES"), &langFull) && !wxGetNonEmptyEnvVar(wxS("LANG"), &langFull)) @@ -656,8 +677,6 @@ inline bool wxGetNonEmptyEnvVar(const wxString& name, wxString* value) return wxLANGUAGE_ENGLISH_US; } -#endif - // the language string has the following form // // lang[_LANG][.encoding][@modifier] From 37a23e1ab1d4fd254379f41b65dcc49befa1a8c9 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 14 Aug 2021 17:42:29 +0100 Subject: [PATCH 19/28] Move platform-specific parts of wxLocale::Init() to wxUILocale This is tidier than using #ifdefs in the same common file and also ensures that initializing wxLocale affects wxUILocale too, which will be important for compatibility when the code elsewhere is modified to use wxUILocale::GetInfo() instead of wxLocale::GetInfo() in the upcoming commits. This commit is best viewed with --color-moved git option. --- include/wx/msw/private/uilocale.h | 28 ++++ include/wx/private/uilocale.h | 9 ++ include/wx/uilocale.h | 6 + include/wx/unix/private/uilocale.h | 33 +++++ src/common/intl.cpp | 199 +++-------------------------- src/common/uilocale.cpp | 12 ++ src/msw/uilocale.cpp | 60 +++++++-- src/osx/core/uilocale.cpp | 21 ++- src/unix/uilocale.cpp | 95 ++++++++++++++ 9 files changed, 270 insertions(+), 193 deletions(-) create mode 100644 include/wx/msw/private/uilocale.h create mode 100644 include/wx/unix/private/uilocale.h diff --git a/include/wx/msw/private/uilocale.h b/include/wx/msw/private/uilocale.h new file mode 100644 index 0000000000..8684213610 --- /dev/null +++ b/include/wx/msw/private/uilocale.h @@ -0,0 +1,28 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/msw/private/uilocale.h +// Purpose: MSW-specific locale-related helpers +// Author: Vadim Zeitlin +// Created: 2021-08-14 +// Copyright: (c) 2021 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_MSW_PRIVATE_UILOCALE_H_ +#define _WX_MSW_PRIVATE_UILOCALE_H_ + +#include "wx/msw/private.h" // Include to get LCID. + +#ifndef LOCALE_SNAME +#define LOCALE_SNAME 0x5c +#endif +#ifndef LOCALE_CUSTOM_UI_DEFAULT +#define LOCALE_CUSTOM_UI_DEFAULT 0x1400 +#endif + +// Use the specific LCID for the current thread. +void wxUseLCID(LCID lcid); + +// This function is defined in src/common/intl.cpp +wxString wxGetInfoFromLCID(LCID lcid, wxLocaleInfo index, wxLocaleCategory cat); + +#endif // _WX_MSW_PRIVATE_UILOCALE_H_ diff --git a/include/wx/private/uilocale.h b/include/wx/private/uilocale.h index 89ce17a63c..bfa6f318ea 100644 --- a/include/wx/private/uilocale.h +++ b/include/wx/private/uilocale.h @@ -33,6 +33,15 @@ public: // It may return NULL in case of failure. static wxUILocaleImpl* CreateUserDefault(); + // This function exists only for wxLocale compatibility and sets the locale + // corresponding to the given language. + // + // The language passed to this function is a valid language, i.e. neither + // wxLANGUAGE_UNKNOWN nor wxLANGUAGE_DEFAULT. + // + // It may return NULL in case of failure. + static wxUILocaleImpl* CreateForLanguage(const wxLanguageInfo& info); + // Functions corresponding to wxUILocale ones. virtual wxString GetName() const = 0; virtual wxString GetInfo(wxLocaleInfo index, wxLocaleCategory cat) const = 0; diff --git a/include/wx/uilocale.h b/include/wx/uilocale.h index f3aa9a2bb3..465baa3ffe 100644 --- a/include/wx/uilocale.h +++ b/include/wx/uilocale.h @@ -29,6 +29,12 @@ public: // Configure the UI to use the default user locale. static bool UseDefault(); + // Use the locale corresponding to the given language. + // + // This is a compatibility function used by wxWidgets itself, don't use it + // in the new code. + static bool UseLanguage(const wxLanguageInfo& info); + // Get the object corresponding to the currently used locale. static const wxUILocale& GetCurrent(); diff --git a/include/wx/unix/private/uilocale.h b/include/wx/unix/private/uilocale.h new file mode 100644 index 0000000000..7a882810d0 --- /dev/null +++ b/include/wx/unix/private/uilocale.h @@ -0,0 +1,33 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/unix/private/uilocale.h +// Purpose: Various locale-related helpers used under Unix systems only +// Author: Vadim Zeitlin +// Created: 2021-08-14 (extracted from src/common/intl.cpp) +// Copyright: (c) 2021 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_UNIX_PRIVATE_UILOCALE_H_ +#define _WX_UNIX_PRIVATE_UILOCALE_H_ + +#include "wx/string.h" + +// get just the language part ("en" in "en_GB") +inline wxString ExtractLang(const wxString& langFull) +{ + return langFull.BeforeFirst('_'); +} + +// get everything else (including the leading '_') +inline wxString ExtractNotLang(const wxString& langFull) +{ + size_t pos = langFull.find('_'); + if ( pos != wxString::npos ) + return langFull.substr(pos); + else + return wxString(); +} + +const char *wxSetlocaleTryAll(int c, const wxString& lc); + +#endif // _WX_UNIX_PRIVATE_UILOCALE_H_ diff --git a/src/common/intl.cpp b/src/common/intl.cpp index e0966452e3..5f2a74788f 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -43,18 +43,6 @@ #include #endif -#ifdef __WIN32__ - #include "wx/dynlib.h" - #include "wx/msw/private.h" - - #ifndef LOCALE_SNAME - #define LOCALE_SNAME 0x5c - #endif - #ifndef LOCALE_CUSTOM_UI_DEFAULT - #define LOCALE_CUSTOM_UI_DEFAULT 0x1400 - #endif -#endif - #include "wx/file.h" #include "wx/filename.h" #include "wx/tokenzr.h" @@ -63,13 +51,18 @@ #include "wx/apptrait.h" #include "wx/stdpaths.h" #include "wx/hashset.h" +#include "wx/uilocale.h" -#if defined(__WXOSX__) +#ifdef __WIN32__ + #include "wx/msw/private/uilocale.h" +#elif defined(__WXOSX__) #include "wx/osx/core/cfref.h" #include "wx/osx/core/cfstring.h" #include #include #include +#elif defined(__UNIX__) + #include "wx/unix/private/uilocale.h" #endif // ---------------------------------------------------------------------------- @@ -88,31 +81,6 @@ static wxLocale *wxSetLocale(wxLocale *pLocale); -namespace -{ - -#if defined(__UNIX__) - -// get just the language part ("en" in "en_GB") -inline wxString ExtractLang(const wxString& langFull) -{ - return langFull.BeforeFirst('_'); -} - -// get everything else (including the leading '_') -inline wxString ExtractNotLang(const wxString& langFull) -{ - size_t pos = langFull.find('_'); - if ( pos != wxString::npos ) - return langFull.substr(pos); - else - return wxString(); -} - -#endif // __UNIX__ - -} // anonymous namespace - // ---------------------------------------------------------------------------- // wxLanguageInfo // ---------------------------------------------------------------------------- @@ -396,89 +364,6 @@ bool wxLocale::DoCommonPostInit(bool success, return success; } -#if defined(__UNIX__) - -// Helper of wxSetlocaleTryAll() below which tries setting the given locale -// with and without UTF-8 suffix. Don't use this one directly. -static const char *wxSetlocaleTryUTF8(int c, const wxString& lc) -{ - const char *l = NULL; - - // NB: We prefer to set UTF-8 locale if it's possible and only fall back to - // non-UTF-8 locale if it fails, but this is not necessary under the - // supported macOS versions where xx_YY locales are just aliases to - // xx_YY.UTF-8 anyhow. -#if wxUSE_UNICODE && !defined(__WXMAC__) - if ( !lc.empty() ) - { - wxString buf(lc); - wxString buf2; - buf2 = buf + wxS(".UTF-8"); - l = wxSetlocale(c, buf2); - if ( !l ) - { - buf2 = buf + wxS(".utf-8"); - l = wxSetlocale(c, buf2); - } - if ( !l ) - { - buf2 = buf + wxS(".UTF8"); - l = wxSetlocale(c, buf2); - } - if ( !l ) - { - buf2 = buf + wxS(".utf8"); - l = wxSetlocale(c, buf2); - } - } - - // if we can't set UTF-8 locale, try non-UTF-8 one: - if ( !l ) -#endif // wxUSE_UNICODE && !__WXMAC__ - l = wxSetlocale(c, lc); - - return l; -} - -// Try setting all possible versions of the given locale, i.e. with and without -// UTF-8 encoding, and with or without the "_territory" part. -static const char *wxSetlocaleTryAll(int c, const wxString& lc) -{ - const char* l = wxSetlocaleTryUTF8(c, lc); - if ( !l ) - { - const wxString& lcOnlyLang = ExtractLang(lc); - if ( lcOnlyLang != lc ) - l = wxSetlocaleTryUTF8(c, lcOnlyLang); - } - - return l; -} - -#endif // __UNIX__ - -#ifdef __WIN32__ - -// Trivial wrapper for ::SetThreadUILanguage(). -// -// TODO-XP: Drop this when we don't support XP any longer. -static void wxMSWSetThreadUILanguage(LANGID langid) -{ - // SetThreadUILanguage() is available on XP, but with unclear - // behavior, so avoid calling it there. - if ( wxGetWinVersion() >= wxWinVersion_Vista ) - { - wxLoadedDLL dllKernel32(wxS("kernel32.dll")); - typedef LANGID(WINAPI *SetThreadUILanguage_t)(LANGID); - SetThreadUILanguage_t pfnSetThreadUILanguage = NULL; - wxDL_INIT_FUNC(pfn, SetThreadUILanguage, dllKernel32); - if (pfnSetThreadUILanguage) - pfnSetThreadUILanguage(langid); - } -} - -#endif // __WIN32__ - bool wxLocale::Init(int lang, int flags) { #if WXWIN_COMPATIBILITY_2_8 @@ -522,62 +407,19 @@ bool wxLocale::Init(int lang, int flags) #if defined(__UNIX__) || defined(__WIN32__) + bool ok = lang == wxLANGUAGE_DEFAULT ? wxUILocale::UseDefault() + : wxUILocale::UseLanguage(*info); + + // Under (non-Darwn) Unix wxUILocale already set the C locale, but under + // the other platforms we still have to do it here. +#if defined(__WIN32__) || defined(__WXOSX__) + // We prefer letting the CRT to set its locale on its own when using // default locale, as it does a better job of it than we do. We also have // to do this when we didn't recognize the default language at all. const char *retloc = lang == wxLANGUAGE_DEFAULT ? wxSetlocale(LC_ALL, "") - : NULL; + : info->TrySetLocale(); -#if defined(__UNIX__) - if ( !retloc ) - retloc = wxSetlocaleTryAll(LC_ALL, shortName); - - if ( !retloc ) - { - // Some C libraries (namely glibc) still use old ISO 639, - // so will translate the abbrev for them - wxString localeAlt; - const wxString& langOnly = ExtractLang(shortName); - if ( langOnly == wxS("he") ) - localeAlt = wxS("iw") + ExtractNotLang(shortName); - else if ( langOnly == wxS("id") ) - localeAlt = wxS("in") + ExtractNotLang(shortName); - else if ( langOnly == wxS("yi") ) - localeAlt = wxS("ji") + ExtractNotLang(shortName); - else if ( langOnly == wxS("nb") ) - localeAlt = wxS("no_NO"); - else if ( langOnly == wxS("nn") ) - localeAlt = wxS("no_NY"); - - if ( !localeAlt.empty() ) - retloc = wxSetlocaleTryAll(LC_ALL, localeAlt); - } -#elif defined(__WIN32__) - if ( lang == wxLANGUAGE_DEFAULT ) - { - ::SetThreadLocale(LOCALE_USER_DEFAULT); - wxMSWSetThreadUILanguage(LANG_USER_DEFAULT); - - // CRT locale already set above. - } - else if ( info->WinLang == 0 ) - { - wxLogWarning(wxS("Locale '%s' not supported by OS."), name); - - retloc = "C"; - } - else // language supported by Windows - { - const wxUint32 lcid = info->GetLCID(); - - // change locale used by Windows functions - ::SetThreadLocale(lcid); - - wxMSWSetThreadUILanguage(LANGIDFROMLCID(lcid)); - - // and also call setlocale() to change locale used by the CRT - retloc = info->TrySetLocale(); - } #if wxUSE_UNICODE && (defined(__VISUALC__) || defined(__MINGW32__)) // VC++ setlocale() (also used by Mingw) can't set locale to languages that // can only be written using Unicode, therefore wxSetlocale() call fails @@ -593,13 +435,15 @@ bool wxLocale::Init(int lang, int flags) } } #endif // CRT not handling Unicode-only languages -#else - #error "Unsupported platform" -#endif + + if ( !retloc ) + ok = false; + +#endif // __WIN32__ return DoCommonPostInit ( - retloc != NULL, + ok, name, // wxLANGUAGE_DEFAULT needs to be passed to wxTranslations as "" // for correct detection of user's preferred language(s) @@ -1123,8 +967,7 @@ wxLocale::~wxLocale() } #ifdef __WIN32__ - ::SetThreadLocale(m_oldLCID); - wxMSWSetThreadUILanguage(LANGIDFROMLCID(m_oldLCID)); + wxUseLCID(m_oldLCID); #endif } diff --git a/src/common/uilocale.cpp b/src/common/uilocale.cpp index bf79b77189..4843f823e5 100644 --- a/src/common/uilocale.cpp +++ b/src/common/uilocale.cpp @@ -53,6 +53,18 @@ bool wxUILocale::UseDefault() return true; } +/* static */ +bool wxUILocale::UseLanguage(const wxLanguageInfo& info) +{ + wxUILocaleImpl* const impl = wxUILocaleImpl::CreateForLanguage(info); + if ( !impl ) + return false; + + ms_current.SetImpl(impl); + + return true; +} + /* static */ const wxUILocale& wxUILocale::GetCurrent() { diff --git a/src/msw/uilocale.cpp b/src/msw/uilocale.cpp index 21070de0c0..6916fefe52 100644 --- a/src/msw/uilocale.cpp +++ b/src/msw/uilocale.cpp @@ -22,22 +22,48 @@ #include "wx/private/uilocale.h" +#include "wx/msw/private/uilocale.h" + #include "wx/dynlib.h" -#include "wx/msw/private.h" - -#ifndef LOCALE_SNAME -#define LOCALE_SNAME 0x5c -#endif - -// This function is defined in src/common/intl.cpp, just declare it here for -// now before refactoring the code. -wxString wxGetInfoFromLCID(LCID lcid, wxLocaleInfo index, wxLocaleCategory cat); - // ============================================================================ // implementation // ============================================================================ +// ---------------------------------------------------------------------------- +// helper functions +// ---------------------------------------------------------------------------- + +namespace +{ + +// Trivial wrapper for ::SetThreadUILanguage(). +// +// TODO-XP: Drop this when we don't support XP any longer. +static void wxMSWSetThreadUILanguage(LANGID langid) +{ + // SetThreadUILanguage() is available on XP, but with unclear + // behavior, so avoid calling it there. + if ( wxGetWinVersion() >= wxWinVersion_Vista ) + { + wxLoadedDLL dllKernel32(wxS("kernel32.dll")); + typedef LANGID(WINAPI *SetThreadUILanguage_t)(LANGID); + SetThreadUILanguage_t pfnSetThreadUILanguage = NULL; + wxDL_INIT_FUNC(pfn, SetThreadUILanguage, dllKernel32); + if (pfnSetThreadUILanguage) + pfnSetThreadUILanguage(langid); + } +} + +} // anonymous namespace + +void wxUseLCID(LCID lcid) +{ + ::SetThreadLocale(lcid); + + wxMSWSetThreadUILanguage(LANGIDFROMLCID(lcid)); +} + // ---------------------------------------------------------------------------- // wxUILocale implementation for MSW // ---------------------------------------------------------------------------- @@ -50,6 +76,7 @@ public: explicit wxUILocaleImplLCID(LCID lcid) : m_lcid(lcid) { + wxUseLCID(lcid); } wxString GetName() const wxOVERRIDE @@ -98,4 +125,17 @@ wxUILocaleImpl* wxUILocaleImpl::CreateUserDefault() return new wxUILocaleImplLCID(LOCALE_USER_DEFAULT); } +/* static */ +wxUILocaleImpl* wxUILocaleImpl::CreateForLanguage(const wxLanguageInfo& info) +{ + if ( info.WinLang == 0 ) + { + wxLogWarning(wxS("Locale '%s' not supported by OS."), info.Description); + + return NULL; + } + + return new wxUILocaleImplLCID(info.GetLCID()); +} + #endif // wxUSE_INTL diff --git a/src/osx/core/uilocale.cpp b/src/osx/core/uilocale.cpp index 3309343739..96a0058f5a 100644 --- a/src/osx/core/uilocale.cpp +++ b/src/osx/core/uilocale.cpp @@ -46,6 +46,15 @@ public: { } + static wxUILocaleImplCF* Create(const wxString& name) + { + CFLocaleRef cfloc = CFLocaleCreate(kCFAllocatorDefault, wxCFStringRef(name)); + if ( !cfloc ) + return NULL; + + return new wxUILocaleImplCF(cfloc); + } + wxString GetName() const wxOVERRIDE; wxString GetInfo(wxLocaleInfo index, wxLocaleCategory cat) const wxOVERRIDE; @@ -76,11 +85,7 @@ wxUILocaleImplCF::GetInfo(wxLocaleInfo index, wxLocaleCategory cat) const /* static */ wxUILocaleImpl* wxUILocaleImpl::CreateStdC() { - CFLocaleRef cfloc = CFLocaleCreate(kCFAllocatorDefault, wxCFStringRef("C")); - if ( !cfloc ) - return NULL; - - return new wxUILocaleImplCF(cfloc); + return wxUILocaleImplCF::Create("C"); } /* static */ @@ -89,4 +94,10 @@ wxUILocaleImpl* wxUILocaleImpl::CreateUserDefault() return new wxUILocaleImplCF(CFLocaleCopyCurrent()); } +/* static */ +wxUILocaleImpl* wxUILocaleImpl::CreateForLanguage(const wxLanguageInfo& info) +{ + return wxUILocaleImplCF::Create(info.CanonicalName); +} + #endif // wxUSE_INTL diff --git a/src/unix/uilocale.cpp b/src/unix/uilocale.cpp index a817ad899d..f4b86fa0a0 100644 --- a/src/unix/uilocale.cpp +++ b/src/unix/uilocale.cpp @@ -22,6 +22,8 @@ #include "wx/private/uilocale.h" +#include "wx/unix/private/uilocale.h" + #include "wx/intl.h" #include @@ -52,6 +54,67 @@ private: // implementation // ============================================================================ +// Helper of wxSetlocaleTryAll() below which tries setting the given locale +// with and without UTF-8 suffix. Don't use this one directly. +static const char *wxSetlocaleTryUTF8(int c, const wxString& lc) +{ + const char *l = NULL; + + // NB: We prefer to set UTF-8 locale if it's possible and only fall back to + // non-UTF-8 locale if it fails, but this is not necessary under the + // supported macOS versions where xx_YY locales are just aliases to + // xx_YY.UTF-8 anyhow. +#if wxUSE_UNICODE && !defined(__WXMAC__) + if ( !lc.empty() ) + { + wxString buf(lc); + wxString buf2; + buf2 = buf + wxS(".UTF-8"); + l = wxSetlocale(c, buf2); + if ( !l ) + { + buf2 = buf + wxS(".utf-8"); + l = wxSetlocale(c, buf2); + } + if ( !l ) + { + buf2 = buf + wxS(".UTF8"); + l = wxSetlocale(c, buf2); + } + if ( !l ) + { + buf2 = buf + wxS(".utf8"); + l = wxSetlocale(c, buf2); + } + } + + // if we can't set UTF-8 locale, try non-UTF-8 one: + if ( !l ) +#endif // wxUSE_UNICODE && !__WXMAC__ + l = wxSetlocale(c, lc); + + return l; +} + +// Try setting all possible versions of the given locale, i.e. with and without +// UTF-8 encoding, and with or without the "_territory" part. +const char *wxSetlocaleTryAll(int c, const wxString& lc) +{ + const char* l = wxSetlocaleTryUTF8(c, lc); + if ( !l ) + { + const wxString& lcOnlyLang = ExtractLang(lc); + if ( lcOnlyLang != lc ) + l = wxSetlocaleTryUTF8(c, lcOnlyLang); + } + + return l; +} + +// ---------------------------------------------------------------------------- +// wxUILocale implementation for Unix +// ---------------------------------------------------------------------------- + wxUILocaleImplUnix::wxUILocaleImplUnix(const char* locale) { if ( locale ) @@ -88,4 +151,36 @@ wxUILocaleImpl* wxUILocaleImpl::CreateUserDefault() return new wxUILocaleImplUnix(""); } +/* static */ +wxUILocaleImpl* wxUILocaleImpl::CreateForLanguage(const wxLanguageInfo& info) +{ + // Set the locale before creating the wxUILocaleImplUnix object in order to + // check if we succeed in doing it. + + const wxString& shortName = info.CanonicalName; + + if ( !wxSetlocaleTryAll(LC_ALL, shortName) ) + { + // Some C libraries (namely glibc) still use old ISO 639, + // so will translate the abbrev for them + wxString localeAlt; + const wxString& langOnly = ExtractLang(shortName); + if ( langOnly == wxS("he") ) + localeAlt = wxS("iw") + ExtractNotLang(shortName); + else if ( langOnly == wxS("id") ) + localeAlt = wxS("in") + ExtractNotLang(shortName); + else if ( langOnly == wxS("yi") ) + localeAlt = wxS("ji") + ExtractNotLang(shortName); + else if ( langOnly == wxS("nb") ) + localeAlt = wxS("no_NO"); + else if ( langOnly == wxS("nn") ) + localeAlt = wxS("no_NY"); + + if ( localeAlt.empty() || !wxSetlocaleTryAll(LC_ALL, localeAlt) ) + return NULL; + } + + return new wxUILocaleImplUnix(NULL); +} + #endif // wxUSE_INTL From b3cab73680df087172867cefc907a37baeb35f49 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Thu, 5 Aug 2021 18:30:30 +0200 Subject: [PATCH 20/28] Use wxUILocale in wxNumberFormatter Always use the UI locale conventions for floating point numbers in wxNumberFormatter, making it different from wxString::{To,From}Double() functions that use C locale, which may, or not, correspond to the UI locale. --- interface/wx/numformatter.h | 18 +++--- src/common/numformatter.cpp | 117 +++++++++--------------------------- 2 files changed, 39 insertions(+), 96 deletions(-) diff --git a/interface/wx/numformatter.h b/interface/wx/numformatter.h index 1479bae1c4..42c260609f 100644 --- a/interface/wx/numformatter.h +++ b/interface/wx/numformatter.h @@ -8,11 +8,15 @@ /** @class wxNumberFormatter - Helper class for formatting and parsing numbers with thousands separators. + Formatting and parsing numbers using the current UI locale conventions, + including support for using the correct decimal point character and + thousands separators. This class contains only static functions, so users must not create instances but directly call the member functions. + @see wxUILocale + @since 2.9.2 @library{wxbase} @@ -32,7 +36,7 @@ public: /** If this flag is given, thousands separators will be inserted in the - number string representation as defined by the current locale. + number string representation as defined by the current UI locale. */ Style_WithThousandsSep = 0x01, @@ -56,7 +60,7 @@ public: Returns string representation of an integer number. By default, the string will use thousands separators if appropriate for - the current locale. This can be avoided by passing Style_None as @a + the current UI locale. This can be avoided by passing Style_None as @a flags in which case the call to the function has exactly the same effect as wxString::Format("%ld", val). @@ -94,7 +98,7 @@ public: Parse a string representation of a number possibly including thousands separators. - These functions parse number representation in the current locale. On + These functions parse number representation in the current UI locale. On success they return @true and store the result at the location pointed to by @a val (which can't be @NULL), otherwise @false is returned. @@ -114,7 +118,7 @@ public: //@} /** - Get the decimal separator for the current locale. + Get the decimal separator for the current UI locale. Decimal separators is always defined and we fall back to returning '.' in case of an error. @@ -123,14 +127,14 @@ public: /** Get the thousands separator if grouping of the digits is used by the - current locale. + current UI locale. The value returned in @a sep should be only used if the function returns @true, otherwise no thousands separator should be used at all. @param sep Points to the variable receiving the thousands separator character - if it is used by the current locale. May be @NULL if only the + if it is used by the current UI locale. May be @NULL if only the function return value is needed. */ static bool GetThousandsSeparatorIfUsed(wxChar *sep); diff --git a/src/common/numformatter.cpp b/src/common/numformatter.cpp index e57ab02335..c7fdd5d012 100644 --- a/src/common/numformatter.cpp +++ b/src/common/numformatter.cpp @@ -16,84 +16,7 @@ #include "wx/numformatter.h" -#include "wx/intl.h" - -#include // for setlocale and LC_ALL - -// ---------------------------------------------------------------------------- -// local helpers -// ---------------------------------------------------------------------------- - -namespace -{ - -// Contains information about the locale which was used to initialize our -// cached values of the decimal and thousands separators. Notice that it isn't -// enough to store just wxLocale because the user code may call setlocale() -// directly and storing just C locale string is not enough because we can use -// the OS API directly instead of the CRT ones on some platforms. So just store -// both. -class LocaleId -{ -public: - LocaleId() - { -#if wxUSE_INTL - m_wxloc = NULL; -#endif // wxUSE_INTL - m_cloc = NULL; - } - - ~LocaleId() - { - Free(); - } - -#if wxUSE_INTL - // Return true if this is the first time this function is called for this - // object or if the program locale has changed since the last time it was - // called. Otherwise just return false indicating that updating locale- - // dependent information is not necessary. - bool NotInitializedOrHasChanged() - { - wxLocale * const wxloc = wxGetLocale(); - const char * const cloc = setlocale(LC_ALL, NULL); - if ( m_wxloc || m_cloc ) - { - if ( m_wxloc == wxloc && strcmp(m_cloc, cloc) == 0 ) - return false; - - Free(); - } - //else: Not initialized yet. - - m_wxloc = wxloc; - m_cloc = wxCRT_StrdupA(cloc); - - return true; - } -#endif // wxUSE_INTL - -private: - void Free() - { -#if wxUSE_INTL - free(m_cloc); -#endif // wxUSE_INTL - } - -#if wxUSE_INTL - // Non-owned pointer to wxLocale which was used. - wxLocale *m_wxloc; -#endif // wxUSE_INTL - - // Owned pointer to the C locale string. - char *m_cloc; - - wxDECLARE_NO_COPY_CLASS(LocaleId); -}; - -} // anonymous namespace +#include "wx/uilocale.h" // ============================================================================ // wxNumberFormatter implementation @@ -111,14 +34,10 @@ wxChar wxNumberFormatter::GetDecimalSeparator() // concurrently from more than one thread so it's not a real problem. static wxChar s_decimalSeparator = 0; - // Remember the locale which was current when we initialized, we must redo - // the initialization if the locale changed. - static LocaleId s_localeUsedForInit; - - if ( s_localeUsedForInit.NotInitializedOrHasChanged() ) + if ( !s_decimalSeparator ) { const wxString - s = wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER); + s = wxUILocale::GetCurrent().GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER); if ( s.length() == 1 ) { s_decimalSeparator = s[0]; @@ -141,12 +60,14 @@ bool wxNumberFormatter::GetThousandsSeparatorIfUsed(wxChar *sep) { #if wxUSE_INTL static wxChar s_thousandsSeparator = 0; - static LocaleId s_localeUsedForInit; + static bool s_thousandsSeparatorInitialized = false; - if ( s_localeUsedForInit.NotInitializedOrHasChanged() ) + if ( !s_thousandsSeparatorInitialized ) { + s_thousandsSeparatorInitialized = true; + const wxString - s = wxLocale::GetInfo(wxLOCALE_THOUSANDS_SEP, wxLOCALE_CAT_NUMBER); + s = wxUILocale::GetCurrent().GetInfo(wxLOCALE_THOUSANDS_SEP, wxLOCALE_CAT_NUMBER); if ( s.length() == 1 ) { s_thousandsSeparator = s[0]; @@ -172,6 +93,21 @@ bool wxNumberFormatter::GetThousandsSeparatorIfUsed(wxChar *sep) // Conversion to string and helpers // ---------------------------------------------------------------------------- +namespace +{ + +void ReplaceSeparatorIfNecessary(wxString& s, wxChar sepOld, wxChar sepNew) +{ + if ( sepNew != sepOld ) + { + const size_t posSep = s.find(sepOld); + if ( posSep != wxString::npos ) + s[posSep] = sepNew; + } +} + +} // anonymous namespace + wxString wxNumberFormatter::PostProcessIntString(wxString s, int style) { if ( style & Style_WithThousandsSep ) @@ -206,7 +142,9 @@ wxString wxNumberFormatter::ToString(wxULongLong_t val, int style) wxString wxNumberFormatter::ToString(double val, int precision, int style) { - wxString s = wxString::FromDouble(val,precision); + wxString s = wxString::FromCDouble(val,precision); + + ReplaceSeparatorIfNecessary(s, '.', GetDecimalSeparator()); if ( style & Style_WithThousandsSep ) AddThousandsSeparators(s); @@ -330,5 +268,6 @@ bool wxNumberFormatter::FromString(wxString s, wxULongLong_t *val) bool wxNumberFormatter::FromString(wxString s, double *val) { RemoveThousandsSeparators(s); - return s.ToDouble(val); + ReplaceSeparatorIfNecessary(s, GetDecimalSeparator(), '.'); + return s.ToCDouble(val); } From 85d379913dfd6676fd79c0a113f6c2d0bc89c19b Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 14 Aug 2021 13:27:57 +0100 Subject: [PATCH 21/28] Use wxUILocale in wxSpinCtrlDouble This ensures that we use the decimal separator corresponding to the UI locale of the application, rather than C locale, so that e.g. comma is used under macOS even if setlocale() is not used. --- include/wx/generic/spinctlg.h | 2 -- src/generic/spinctlg.cpp | 7 +++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/include/wx/generic/spinctlg.h b/include/wx/generic/spinctlg.h index 64d9cb95c5..bba53839c9 100644 --- a/include/wx/generic/spinctlg.h +++ b/include/wx/generic/spinctlg.h @@ -427,8 +427,6 @@ private: void DoSetDigitsAndUpdate(unsigned digits); - wxString m_format; - wxDECLARE_DYNAMIC_CLASS(wxSpinCtrlDouble); }; diff --git a/src/generic/spinctlg.cpp b/src/generic/spinctlg.cpp index ae47212210..ff4a40e938 100644 --- a/src/generic/spinctlg.cpp +++ b/src/generic/spinctlg.cpp @@ -41,6 +41,7 @@ wxIMPLEMENT_DYNAMIC_CLASS(wxSpinDoubleEvent, wxNotifyEvent); #if wxUSE_SPINBTN +#include "wx/numformatter.h" #include "wx/valnum.h" #include "wx/valtext.h" @@ -754,12 +755,12 @@ void wxSpinCtrlDouble::DoSendEvent() bool wxSpinCtrlDouble::DoTextToValue(const wxString& text, double *val) { - return text.ToDouble(val); + return wxNumberFormatter::FromString(text, val); } wxString wxSpinCtrlDouble::DoValueToText(double val) { - return wxString::Format(m_format, val); + return wxNumberFormatter::ToString(val, m_digits); } void wxSpinCtrlDouble::SetIncrement(double inc) @@ -802,8 +803,6 @@ void wxSpinCtrlDouble::DoSetDigitsAndUpdate(unsigned digits) void wxSpinCtrlDouble::DoSetDigits(unsigned digits) { m_digits = digits; - - m_format.Printf(wxT("%%0.%ulf"), digits); } void wxSpinCtrlDouble::ResetTextValidator() From 3fc031e75b0fef994d3562bc653c5982477adf66 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 14 Aug 2021 13:59:17 +0100 Subject: [PATCH 22/28] Add wxNumberFormatter::Format() for floating point numbers The existing ToString() is not flexible enough to be used in wxGrid, which supports specifying the width (and not just the precision) as well as using formats other than "%g" and "%f" which are the only ones supported by the existing function. Note that currently the implementation simply calls wxString::Format() and then adjusts the decimal separator, but it could, in principle, use wxUILocale methods for formatting the floating point numbers using native platform functions for doing this, e.g. CFNumberFormatter under macOS. --- include/wx/numformatter.h | 7 +++++++ interface/wx/numformatter.h | 10 ++++++++++ src/common/numformatter.cpp | 17 +++++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/include/wx/numformatter.h b/include/wx/numformatter.h index 24ab702ab7..5e0f795dbe 100644 --- a/include/wx/numformatter.h +++ b/include/wx/numformatter.h @@ -40,6 +40,13 @@ public: int precision, int style = Style_WithThousandsSep); + // Format the given number using one of the floating point formats and + // ensure that the result uses the correct decimal separator. + // Prefer using ToString() if possible, i.e. if format is "%g" or "%.Nf" + // which are supported by it directly. + static wxString Format(const wxString& format, double val); + + // Parse a string representing a number, possibly with thousands separator. // // Return true on success and stores the result in the provided location diff --git a/interface/wx/numformatter.h b/interface/wx/numformatter.h index 42c260609f..f635e2327d 100644 --- a/interface/wx/numformatter.h +++ b/interface/wx/numformatter.h @@ -93,6 +93,16 @@ public: static wxString ToString(double val, int precision, int flags = Style_WithThousandsSep); + /** + Format the given number using one of the floating point formats and + ensure that the result uses the correct decimal separator. + + Prefer using ToString() if possible, i.e. if format is "%g" or "%.Nf" + which are supported by it directly. + + @since 3.1.6 + */ + static wxString Format(const wxString& format, double val); /** Parse a string representation of a number possibly including thousands diff --git a/src/common/numformatter.cpp b/src/common/numformatter.cpp index c7fdd5d012..c59ea520db 100644 --- a/src/common/numformatter.cpp +++ b/src/common/numformatter.cpp @@ -155,6 +155,23 @@ wxString wxNumberFormatter::ToString(double val, int precision, int style) return s; } +wxString wxNumberFormatter::Format(const wxString& format, double val) +{ + wxString s = wxString::Format(format, val); + + const wxChar sep = GetDecimalSeparator(); + if ( s.find(sep) == wxString::npos ) + { + const wxChar other = sep == '.' ? ',' : '.'; + const size_t posSep = s.find(other); + if ( posSep != wxString::npos ) + s[posSep] = sep; + } + //else: it already uses the correct separator + + return s; +} + void wxNumberFormatter::AddThousandsSeparators(wxString& s) { // Thousands separators for numbers in scientific format are not relevant. From e438f9a496b7026d531d3398ab6cc1df34b3fa4b Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 14 Aug 2021 14:02:16 +0100 Subject: [PATCH 23/28] Use wxNumberFormatter in wxGrid number renderer and editor This ensures that the correct, i.e. matching the users default, decimal point separator is used even if setlocale() is not called. Also simplify the code a bit by removing checks for wxUSE_INTL already present in wxNumberFormatter itself. --- src/generic/gridctrl.cpp | 6 +++--- src/generic/grideditors.cpp | 29 ++++++----------------------- 2 files changed, 9 insertions(+), 26 deletions(-) diff --git a/src/generic/gridctrl.cpp b/src/generic/gridctrl.cpp index 8ba3582b2c..0732fd4520 100644 --- a/src/generic/gridctrl.cpp +++ b/src/generic/gridctrl.cpp @@ -25,6 +25,7 @@ #include "wx/checkbox.h" #endif // WX_PRECOMP +#include "wx/numformatter.h" #include "wx/tokenzr.h" #include "wx/renderer.h" @@ -839,7 +840,7 @@ wxString wxGridCellFloatRenderer::GetString(const wxGrid& grid, int row, int col else { text = table->GetValue(row, col); - hasDouble = text.ToDouble(&val); + hasDouble = wxNumberFormatter::FromString(text, &val); } if ( hasDouble ) @@ -877,8 +878,7 @@ wxString wxGridCellFloatRenderer::GetString(const wxGrid& grid, int row, int col m_format += wxT('f'); } - text.Printf(m_format, val); - + text = wxNumberFormatter::Format(m_format, val); } //else: text already contains the string diff --git a/src/generic/grideditors.cpp b/src/generic/grideditors.cpp index 6cdce725eb..b4fcbce48b 100644 --- a/src/generic/grideditors.cpp +++ b/src/generic/grideditors.cpp @@ -29,6 +29,7 @@ #include "wx/listbox.h" #endif +#include "wx/numformatter.h" #include "wx/valnum.h" #include "wx/textfile.h" #include "wx/spinctrl.h" @@ -997,7 +998,7 @@ void wxGridCellFloatEditor::BeginEdit(int row, int col, wxGrid* grid) const wxString value = table->GetValue(row, col); if ( !value.empty() ) { - if ( !value.ToDouble(&m_value) ) + if ( !wxNumberFormatter::FromString(value, &m_value) ) { wxFAIL_MSG( wxT("this cell doesn't have float value") ); return; @@ -1018,7 +1019,7 @@ bool wxGridCellFloatEditor::EndEdit(int WXUNUSED(row), double value; if ( !text.empty() ) { - if ( !text.ToDouble(&value) ) + if ( !wxNumberFormatter::FromString(text, &value) ) return false; } else // new value is empty string @@ -1060,20 +1061,9 @@ void wxGridCellFloatEditor::Reset() void wxGridCellFloatEditor::StartingKey(wxKeyEvent& event) { int keycode = event.GetKeyCode(); - char tmpbuf[2]; - tmpbuf[0] = (char) keycode; - tmpbuf[1] = '\0'; - wxString strbuf(tmpbuf, *wxConvCurrent); - -#if wxUSE_INTL - bool is_decimal_point = ( strbuf == - wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER) ); -#else - bool is_decimal_point = ( strbuf == wxT(".") ); -#endif if ( wxIsdigit(keycode) || keycode == '+' || keycode == '-' - || is_decimal_point ) + || keycode == wxNumberFormatter::GetDecimalSeparator() ) { wxGridCellTextEditor::StartingKey(event); @@ -1197,7 +1187,7 @@ wxString wxGridCellFloatEditor::GetString() m_format += wxT('f'); } - return wxString::Format(m_format, m_value); + return wxNumberFormatter::Format(m_format, m_value); } bool wxGridCellFloatEditor::IsAcceptedKey(wxKeyEvent& event) @@ -1207,17 +1197,10 @@ bool wxGridCellFloatEditor::IsAcceptedKey(wxKeyEvent& event) const int keycode = event.GetKeyCode(); if ( wxIsascii(keycode) ) { -#if wxUSE_INTL - const wxString decimalPoint = - wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER); -#else - const wxString decimalPoint(wxT('.')); -#endif - // accept digits, 'e' as in '1e+6', also '-', '+', and '.' if ( wxIsdigit(keycode) || tolower(keycode) == 'e' || - keycode == decimalPoint || + keycode == wxNumberFormatter::GetDecimalSeparator() || keycode == '+' || keycode == '-' ) { From 8fa853a3e26b5e6e837e73d94b95b931fda104a9 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 14 Aug 2021 19:08:21 +0100 Subject: [PATCH 24/28] Add wxGetUIDateFormat() helper function Retrieve thr date format to use, even when wxUSE_INTL==0. --- include/wx/uilocale.h | 14 +++++++++++++- interface/wx/uilocale.h | 15 +++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/include/wx/uilocale.h b/include/wx/uilocale.h index 465baa3ffe..acae223190 100644 --- a/include/wx/uilocale.h +++ b/include/wx/uilocale.h @@ -67,6 +67,18 @@ private: wxDECLARE_NO_COPY_CLASS(wxUILocale); }; -#endif // wxUSE_INTL +inline wxString wxGetUIDateFormat() +{ + return wxUILocale::GetCurrent().GetInfo(wxLOCALE_SHORT_DATE_FMT); +} + +#else // !wxUSE_INTL + +inline wxString wxGetUIDateFormat() +{ + return wxString(wxS("%x")); +} + +#endif // wxUSE_INTL/!wxUSE_INTL #endif // _WX_UILOCALE_H_ diff --git a/interface/wx/uilocale.h b/interface/wx/uilocale.h index d31eaf1b89..de6bcc7550 100644 --- a/interface/wx/uilocale.h +++ b/interface/wx/uilocale.h @@ -104,3 +104,18 @@ public: wxString GetInfo(wxLocaleInfo index, wxLocaleCategory cat = wxLOCALE_CAT_DEFAULT) const; }; + +/** + Return the format to use for formatting user-visible dates. + + This is a simple wrapper function normally calling wxUILocale::GetInfo() + with wxLOCALE_SHORT_DATE_FMT argument, but which is also available when @c + wxUSE_INTL==0, i.e. support for internationalization is disabled at + compile-time, in which case it returns @c %x string, i.e. uses the current + C locale formatting rather than UI locale. + + @see wxDateTime::Format() + + @since 3.1.6 + */ +wxString wxGetUIDateFormat(); From d08fc7575e3def48b5d94fd5881a80cfcb258ce0 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 14 Aug 2021 14:10:31 +0100 Subject: [PATCH 25/28] Use wxUILocale for formatting dates in wxGrid This is similar to the previous commit and ensures that the correct date format is used even if setlocale() is not called. --- src/generic/gridctrl.cpp | 3 ++- src/generic/grideditors.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/generic/gridctrl.cpp b/src/generic/gridctrl.cpp index 0732fd4520..4c526f81b5 100644 --- a/src/generic/gridctrl.cpp +++ b/src/generic/gridctrl.cpp @@ -28,6 +28,7 @@ #include "wx/numformatter.h" #include "wx/tokenzr.h" #include "wx/renderer.h" +#include "wx/uilocale.h" #include "wx/generic/private/grid.h" #include "wx/private/window.h" @@ -160,7 +161,7 @@ wxGridCellDateRenderer::wxGridCellDateRenderer(const wxString& outformat) { if ( outformat.empty() ) { - m_oformat = "%x"; // Localized date representation. + m_oformat = wxGetUIDateFormat(); } else { diff --git a/src/generic/grideditors.cpp b/src/generic/grideditors.cpp index b4fcbce48b..96832ee9de 100644 --- a/src/generic/grideditors.cpp +++ b/src/generic/grideditors.cpp @@ -36,6 +36,7 @@ #include "wx/tokenzr.h" #include "wx/renderer.h" #include "wx/datectrl.h" +#include "wx/uilocale.h" #include "wx/generic/gridsel.h" #include "wx/generic/grideditors.h" @@ -1852,7 +1853,7 @@ wxGridCellDateEditor::wxGridCellDateEditor(const wxString& format) void wxGridCellDateEditor::SetParameters(const wxString& params) { if ( params.empty() ) - m_format = "%x"; + m_format = wxGetUIDateFormat(); else m_format = params; } From 8373b14280b8e51ad88111d1dc2afcd370cc9f98 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 14 Aug 2021 14:48:33 +0100 Subject: [PATCH 26/28] Add a wxGrid with numbers and dates to the internat sample Show that the numbers and dates in wxGrid use the expected formats. --- samples/internat/internat.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/samples/internat/internat.cpp b/samples/internat/internat.cpp index 2bd0af7af0..37baad345f 100644 --- a/samples/internat/internat.cpp +++ b/samples/internat/internat.cpp @@ -31,6 +31,7 @@ #include "wx/calctrl.h" #include "wx/intl.h" #include "wx/file.h" +#include "wx/grid.h" #include "wx/log.h" #include "wx/cmdline.h" #include "wx/numformatter.h" @@ -382,6 +383,23 @@ MyFrame::MyFrame() topSizer->Add(new wxCalendarCtrl(panel, wxID_ANY), wxSizerFlags().Center().Border()); + // another control using locale-specific number and date format + wxGrid* const grid = new wxGrid(panel, wxID_ANY, + wxDefaultPosition, wxDefaultSize, + wxBORDER_SIMPLE); + grid->CreateGrid(2, 2); + grid->HideRowLabels(); + + grid->SetColLabelValue(0, _("Number")); + grid->SetColFormatFloat(0); + grid->SetCellValue(0, 0, wxNumberFormatter::ToString(3.14159265, -1)); + + grid->SetColLabelValue(1, _("Date")); + grid->SetColFormatDate(1); + grid->SetCellValue(0, 1, "Today"); + + topSizer->Add(grid, wxSizerFlags().Center().Border()); + // show the difference between wxString::Format() and wxNumberFormatter: // the former uses the current C locale, while the latter uses the UI // locale From c746953f9b8b255a7eda48b112ae906f9f95cc44 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 14 Aug 2021 19:08:43 +0100 Subject: [PATCH 27/28] Use wxUILocale for date formatting in wxDataViewDateRenderer Use the appropriate format for the dates by using the UI, rather than C, locale, similarly to wxGrid. --- include/wx/dvrenderers.h | 2 ++ src/common/datavcmn.cpp | 13 ++++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/include/wx/dvrenderers.h b/include/wx/dvrenderers.h index 85fcea0023..3b6857e971 100644 --- a/include/wx/dvrenderers.h +++ b/include/wx/dvrenderers.h @@ -527,6 +527,8 @@ public: virtual wxSize GetSize() const wxOVERRIDE; private: + wxString FormatDate() const; + wxDateTime m_date; }; #else // !wxUSE_DATEPICKCTRL diff --git a/src/common/datavcmn.cpp b/src/common/datavcmn.cpp index 2c6fbe11d1..3824218eae 100644 --- a/src/common/datavcmn.cpp +++ b/src/common/datavcmn.cpp @@ -28,6 +28,8 @@ #include "wx/choice.h" #include "wx/imaglist.h" #include "wx/renderer.h" +#include "wx/uilocale.h" + #if wxUSE_ACCESSIBILITY #include "wx/access.h" #endif // wxUSE_ACCESSIBILITY @@ -1986,23 +1988,28 @@ bool wxDataViewDateRenderer::GetValue(wxVariant& value) const return true; } +wxString wxDataViewDateRenderer::FormatDate() const +{ + return m_date.Format(wxGetUIDateFormat()); +} + #if wxUSE_ACCESSIBILITY wxString wxDataViewDateRenderer::GetAccessibleDescription() const { - return m_date.FormatDate(); + return FormatDate(); } #endif // wxUSE_ACCESSIBILITY bool wxDataViewDateRenderer::Render(wxRect cell, wxDC* dc, int state) { - wxString tmp = m_date.FormatDate(); + wxString tmp = FormatDate(); RenderText( tmp, 0, cell, dc, state ); return true; } wxSize wxDataViewDateRenderer::GetSize() const { - return GetTextExtent(m_date.FormatDate()); + return GetTextExtent(FormatDate()); } #endif // (defined(wxHAS_GENERIC_DATAVIEWCTRL) || defined(__WXGTK__)) && wxUSE_DATEPICKCTRL From 9205209099477234667efdae816d4dac0dadd446 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 15 Aug 2021 15:02:21 +0200 Subject: [PATCH 28/28] Demonstrate the thousands separator in internat sample too Use a number > 1000 to show the difference between the locales. --- samples/internat/internat.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/samples/internat/internat.cpp b/samples/internat/internat.cpp index 37baad345f..15f8319239 100644 --- a/samples/internat/internat.cpp +++ b/samples/internat/internat.cpp @@ -400,9 +400,10 @@ MyFrame::MyFrame() topSizer->Add(grid, wxSizerFlags().Center().Border()); - // show the difference between wxString::Format() and wxNumberFormatter: - // the former uses the current C locale, while the latter uses the UI - // locale + // show the difference (in decimal and thousand separator, hence use a + // floating point number > 1000) between wxString::Format() and + // wxNumberFormatter: the former uses the current C locale, while the + // latter uses the UI locale topSizer->Add(new wxStaticText ( panel, @@ -410,8 +411,8 @@ MyFrame::MyFrame() wxString::Format ( _("Number in UI locale: %s; in C locale: %.2f"), - wxNumberFormatter::ToString(5.67, 2), - 5.67 + wxNumberFormatter::ToString(1234567.89, 2), + 1234567.89 ) ), wxSizerFlags().Center().Border());