Add wxUILocale::CompareStrings() function
This function allows comparing strings using the sort order of the specified locale, represented by the new wxLocaleIdent class. It is implemented using CompareStringEx()[1] under MSW and NSString::compare:options:range:locale:[2] under macOS, generic implementation for the other platforms is upcoming. [1]: https://docs.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-comparestringex [2]: https://developer.apple.com/documentation/foundation/nsstring/1414561-compare?language=objc
This commit is contained in:
committed by
Vadim Zeitlin
parent
9f43ec03e6
commit
c8269210a2
@@ -108,6 +108,63 @@ struct WXDLLIMPEXP_BASE wxLanguageInfo
|
|||||||
const char* TrySetLocale() const;
|
const char* TrySetLocale() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// wxLocaleIdent: allows to fully identify a locale under all platforms
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class WXDLLIMPEXP_BASE wxLocaleIdent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Leave language empty
|
||||||
|
wxLocaleIdent() { }
|
||||||
|
|
||||||
|
// Construct name from language
|
||||||
|
wxLocaleIdent(const wxString& language) : m_language(language) { }
|
||||||
|
|
||||||
|
// Set language
|
||||||
|
wxLocaleIdent& Language(const wxString& language)
|
||||||
|
{
|
||||||
|
m_language = language;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set region
|
||||||
|
wxLocaleIdent& Region(const wxString& region)
|
||||||
|
{
|
||||||
|
m_region = region;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set script
|
||||||
|
wxLocaleIdent& Script(const wxString& script)
|
||||||
|
{
|
||||||
|
m_script = script;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set modifier
|
||||||
|
wxLocaleIdent& Modifier(const wxString& modifier)
|
||||||
|
{
|
||||||
|
m_modifier = modifier;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct platform dependent name
|
||||||
|
wxString GetName() const;
|
||||||
|
|
||||||
|
// Empty language represents user's default language
|
||||||
|
bool IsDefault() const
|
||||||
|
{
|
||||||
|
return m_language.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
wxString m_language;
|
||||||
|
wxString m_region;
|
||||||
|
wxString m_script;
|
||||||
|
wxString m_modifier;
|
||||||
|
};
|
||||||
|
|
||||||
#endif // wxUSE_INTL
|
#endif // wxUSE_INTL
|
||||||
|
|
||||||
#endif // _WX_LOCALEDEFS_H_
|
#endif // _WX_LOCALEDEFS_H_
|
||||||
|
@@ -45,6 +45,10 @@ public:
|
|||||||
wxString GetInfo(wxLocaleInfo index,
|
wxString GetInfo(wxLocaleInfo index,
|
||||||
wxLocaleCategory cat = wxLOCALE_CAT_DEFAULT) const;
|
wxLocaleCategory cat = wxLOCALE_CAT_DEFAULT) const;
|
||||||
|
|
||||||
|
// Compares two strings, for a locale specified by wxLocaleIdent.
|
||||||
|
static int CompareStrings(const wxString& lhs, const wxString& rhs,
|
||||||
|
const wxLocaleIdent& localeId = wxLocaleIdent());
|
||||||
|
|
||||||
// Note that this class is not supposed to be used polymorphically, hence
|
// Note that this class is not supposed to be used polymorphically, hence
|
||||||
// its dtor is not virtual.
|
// its dtor is not virtual.
|
||||||
~wxUILocale();
|
~wxUILocale();
|
||||||
|
@@ -80,6 +80,24 @@ public:
|
|||||||
*/
|
*/
|
||||||
static const wxUILocale& GetCurrent();
|
static const wxUILocale& GetCurrent();
|
||||||
|
|
||||||
|
/**
|
||||||
|
Compares two strings using comparison rules of the given locale.
|
||||||
|
|
||||||
|
@param lhs
|
||||||
|
First comparing string.
|
||||||
|
@param rhs
|
||||||
|
Second comparing string.
|
||||||
|
@param localeId
|
||||||
|
Represents platform dependent language name.
|
||||||
|
@see wxLocaleIdent for details.
|
||||||
|
@return
|
||||||
|
-1 if lhs less than rhs.
|
||||||
|
0 if lhs equal to rhs.
|
||||||
|
1 if lhs greater than rhs.
|
||||||
|
*/
|
||||||
|
static int CompareStrings(const wxString& lhs, const wxString& rhs,
|
||||||
|
const wxLocaleIdent& localeId = wxLocaleIdent());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Get the platform-dependent name of the current locale.
|
Get the platform-dependent name of the current locale.
|
||||||
|
|
||||||
@@ -119,3 +137,93 @@ public:
|
|||||||
@since 3.1.6
|
@since 3.1.6
|
||||||
*/
|
*/
|
||||||
wxString wxGetUIDateFormat();
|
wxString wxGetUIDateFormat();
|
||||||
|
|
||||||
|
/**
|
||||||
|
Allows to construct the full locale identifier in a portable way.
|
||||||
|
|
||||||
|
Parts of the locale not supported by the current platform (e.g. modifier under non-Unix platforms) are ignored.
|
||||||
|
The remaining parts are used to construct a string uniquely identifying the locale in a platform-specific name.
|
||||||
|
|
||||||
|
Usage example:
|
||||||
|
@code
|
||||||
|
auto loc = wxLocaleIdent("fr").Region("BE").Modifier("euro");
|
||||||
|
#if defined(__WINDOWS__) || defined(__WXOSX__)
|
||||||
|
wxASSERT( loc.GetName() == "fr_BE" );
|
||||||
|
#elif defined(__UNIX__)
|
||||||
|
wxASSERT( loc.GetName() == "fr_BE@euro" );
|
||||||
|
#endif
|
||||||
|
@endcode
|
||||||
|
@since 3.1.6
|
||||||
|
*/
|
||||||
|
class wxLocaleIdent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
This is the default constructor and it leaves language empty.
|
||||||
|
*/
|
||||||
|
wxLocaleIdent();
|
||||||
|
|
||||||
|
/**
|
||||||
|
Constructor with language.
|
||||||
|
|
||||||
|
@param language
|
||||||
|
ISO 639 language code.
|
||||||
|
See Language() for more detailed info.
|
||||||
|
*/
|
||||||
|
wxLocaleIdent(const wxString& language);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Set language.
|
||||||
|
Return reference to @this for method chaining.
|
||||||
|
|
||||||
|
@param language
|
||||||
|
It is a lowercase ISO 639 language code.
|
||||||
|
The codes from ISO 639-1 are used when available.
|
||||||
|
Otherwise, codes from ISO 639-2/T are used.
|
||||||
|
*/
|
||||||
|
wxLocaleIdent& Language(const wxString& language);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Set region.
|
||||||
|
Return reference to @this for method chaining.
|
||||||
|
|
||||||
|
@param region
|
||||||
|
It specifies an uppercase ISO 3166-1 country/region identifier.
|
||||||
|
*/
|
||||||
|
wxLocaleIdent& Region(const wxString& region);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Set script.
|
||||||
|
Return reference to @this for method chaining.
|
||||||
|
|
||||||
|
@param script
|
||||||
|
It is an initial-uppercase ISO 15924 script code.
|
||||||
|
*/
|
||||||
|
wxLocaleIdent& Script(const wxString& script);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Set modifier.
|
||||||
|
Return reference to @this for method chaining.
|
||||||
|
|
||||||
|
@param modifier
|
||||||
|
Modifier is defined by ISO/IEC 15897.
|
||||||
|
It is a semi-colon separated list of identifiers, or name=value pairs.
|
||||||
|
*/
|
||||||
|
wxLocaleIdent& Modifier(const wxString& modifier);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Construct platform dependent name.
|
||||||
|
Format:
|
||||||
|
Windows: <language>-<script>-<REGION>
|
||||||
|
Unix: <language>_<REGION>@<modifier>
|
||||||
|
MacOS: <language>-<script>_<REGION>
|
||||||
|
*/
|
||||||
|
wxString GetName() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Empty language represents user's default language.
|
||||||
|
|
||||||
|
@return @true if language is empty, @false otherwise.
|
||||||
|
*/
|
||||||
|
bool IsDefault() const;
|
||||||
|
};
|
||||||
|
@@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#if wxUSE_INTL
|
#if wxUSE_INTL
|
||||||
|
|
||||||
|
#include "wx/uilocale.h"
|
||||||
#include "wx/private/uilocale.h"
|
#include "wx/private/uilocale.h"
|
||||||
|
|
||||||
#include "wx/msw/private/uilocale.h"
|
#include "wx/msw/private/uilocale.h"
|
||||||
@@ -55,6 +56,43 @@ static void wxMSWSetThreadUILanguage(LANGID langid)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Trivial wrapper for ::CompareStringEx().
|
||||||
|
//
|
||||||
|
// TODO-XP: Drop this when we don't support XP any longer.
|
||||||
|
static int wxMSWCompareStringEx(LPCWSTR lpLocaleName,
|
||||||
|
DWORD dwCmpFlags,
|
||||||
|
LPCWSTR lpString1, //_In_NLS_string_(cchCount1)LPCWCH lpString1,
|
||||||
|
int cchCount1,
|
||||||
|
LPCWSTR lpString2, //_In_NLS_string_(cchCount2)LPCWCH lpString2,
|
||||||
|
int cchCount2,
|
||||||
|
LPNLSVERSIONINFO lpVersionInformation,
|
||||||
|
LPVOID lpReserved,
|
||||||
|
LPARAM lParam)
|
||||||
|
{
|
||||||
|
typedef int(WINAPI *CompareStringEx_t)(LPCWSTR,DWORD,LPCWSTR,int,LPCWSTR,int,LPNLSVERSIONINFO,LPVOID,LPARAM);
|
||||||
|
static const CompareStringEx_t INVALID_FUNC_PTR = (CompareStringEx_t)-1;
|
||||||
|
|
||||||
|
static CompareStringEx_t pfnCompareStringEx = INVALID_FUNC_PTR;
|
||||||
|
|
||||||
|
if (pfnCompareStringEx == INVALID_FUNC_PTR)
|
||||||
|
{
|
||||||
|
// Avoid calling CompareStringEx() on XP.
|
||||||
|
if (wxGetWinVersion() >= wxWinVersion_Vista)
|
||||||
|
{
|
||||||
|
wxLoadedDLL dllKernel32(wxS("kernel32.dll"));
|
||||||
|
wxDL_INIT_FUNC(pfn, CompareStringEx, dllKernel32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pfnCompareStringEx)
|
||||||
|
{
|
||||||
|
return pfnCompareStringEx(lpLocaleName, dwCmpFlags, lpString1, cchCount1, lpString2,
|
||||||
|
cchCount2, lpVersionInformation, lpReserved, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
void wxUseLCID(LCID lcid)
|
void wxUseLCID(LCID lcid)
|
||||||
@@ -64,6 +102,34 @@ void wxUseLCID(LCID lcid)
|
|||||||
wxMSWSetThreadUILanguage(LANGIDFROMLCID(lcid));
|
wxMSWSetThreadUILanguage(LANGIDFROMLCID(lcid));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// wxLocaleIdent::GetName() implementation for MSW
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
wxString wxLocaleIdent::GetName() const
|
||||||
|
{
|
||||||
|
// Construct name in right format:
|
||||||
|
// Windows: <language>-<script>-<REGION>
|
||||||
|
|
||||||
|
wxString name;
|
||||||
|
if ( !m_language.empty() )
|
||||||
|
{
|
||||||
|
name << m_language;
|
||||||
|
|
||||||
|
if ( !m_script.empty() )
|
||||||
|
{
|
||||||
|
name << "-" << m_script;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !m_region.empty() )
|
||||||
|
{
|
||||||
|
name << "-" << m_region;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// wxUILocale implementation for MSW
|
// wxUILocale implementation for MSW
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@@ -138,4 +204,30 @@ wxUILocaleImpl* wxUILocaleImpl::CreateForLanguage(const wxLanguageInfo& info)
|
|||||||
return new wxUILocaleImplLCID(info.GetLCID());
|
return new wxUILocaleImplLCID(info.GetLCID());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* static */
|
||||||
|
int wxUILocale::CompareStrings(const wxString& lhs, const wxString& rhs, const wxLocaleIdent& locale_id)
|
||||||
|
{
|
||||||
|
int ret = wxMSWCompareStringEx(
|
||||||
|
locale_id.IsDefault() ? LOCALE_NAME_USER_DEFAULT
|
||||||
|
: static_cast<LPCWSTR>(
|
||||||
|
locale_id.GetName().wc_str()
|
||||||
|
),
|
||||||
|
0, // Maybe we need LINGUISTIC_IGNORECASE here
|
||||||
|
static_cast<LPCWSTR>(lhs.wc_str()), -1,
|
||||||
|
static_cast<LPCWSTR>(rhs.wc_str()), -1,
|
||||||
|
NULL, NULL, 0);
|
||||||
|
|
||||||
|
switch (ret)
|
||||||
|
{
|
||||||
|
case CSTR_LESS_THAN:
|
||||||
|
return -1;
|
||||||
|
case CSTR_EQUAL:
|
||||||
|
return 0;
|
||||||
|
case CSTR_GREATER_THAN:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#endif // wxUSE_INTL
|
#endif // wxUSE_INTL
|
||||||
|
@@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#if wxUSE_INTL
|
#if wxUSE_INTL
|
||||||
|
|
||||||
|
#include "wx/uilocale.h"
|
||||||
#include "wx/private/uilocale.h"
|
#include "wx/private/uilocale.h"
|
||||||
|
|
||||||
#include "wx/osx/core/cfref.h"
|
#include "wx/osx/core/cfref.h"
|
||||||
@@ -28,9 +29,40 @@
|
|||||||
#include <CoreFoundation/CFLocale.h>
|
#include <CoreFoundation/CFLocale.h>
|
||||||
#include <CoreFoundation/CFString.h>
|
#include <CoreFoundation/CFString.h>
|
||||||
|
|
||||||
|
#import <Foundation/NSString.h>
|
||||||
|
#import <Foundation/NSLocale.h>
|
||||||
|
|
||||||
extern wxString
|
extern wxString
|
||||||
wxGetInfoFromCFLocale(CFLocaleRef cfloc, wxLocaleInfo index, wxLocaleCategory cat);
|
wxGetInfoFromCFLocale(CFLocaleRef cfloc, wxLocaleInfo index, wxLocaleCategory cat);
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// wxLocaleIdent::GetName() implementation using Foundation
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
wxString wxLocaleIdent::GetName() const
|
||||||
|
{
|
||||||
|
// Construct name in right format:
|
||||||
|
// MacOS: <language>-<script>_<REGION>
|
||||||
|
|
||||||
|
wxString name;
|
||||||
|
if ( !m_language.empty() )
|
||||||
|
{
|
||||||
|
name << m_language;
|
||||||
|
|
||||||
|
if ( !m_script.empty() )
|
||||||
|
{
|
||||||
|
name << "-" << m_script;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !m_region.empty() )
|
||||||
|
{
|
||||||
|
name << "_" << m_region;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -100,4 +132,34 @@ wxUILocaleImpl* wxUILocaleImpl::CreateForLanguage(const wxLanguageInfo& info)
|
|||||||
return wxUILocaleImplCF::Create(info.CanonicalName);
|
return wxUILocaleImplCF::Create(info.CanonicalName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* static */
|
||||||
|
int wxUILocale::CompareStrings(const wxString& lhs, const wxString& rhs, const wxLocaleIdent& locale_id)
|
||||||
|
{
|
||||||
|
NSString *ns_lhs = [NSString stringWithCString:lhs.ToStdString(wxConvUTF8).c_str()
|
||||||
|
encoding:NSUTF8StringEncoding];
|
||||||
|
NSString *ns_rhs = [NSString stringWithCString:rhs.ToStdString(wxConvUTF8).c_str()
|
||||||
|
encoding:NSUTF8StringEncoding];
|
||||||
|
NSString *ns_locale_id = [NSString stringWithCString:locale_id.GetName().ToStdString(wxConvUTF8).c_str()
|
||||||
|
encoding:NSUTF8StringEncoding];
|
||||||
|
NSInteger options = NSCaseInsensitiveSearch; // Maybe also NSDiacriticInsensitiveSearch?
|
||||||
|
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:ns_locale_id];
|
||||||
|
|
||||||
|
NSComparisonResult ret = [ns_lhs compare:ns_rhs
|
||||||
|
options:options
|
||||||
|
range:(NSRange){0, [ns_lhs length]}
|
||||||
|
locale:locale];
|
||||||
|
|
||||||
|
switch (ret)
|
||||||
|
{
|
||||||
|
case NSOrderedAscending:
|
||||||
|
return -1;
|
||||||
|
case NSOrderedSame:
|
||||||
|
return 0;
|
||||||
|
case NSOrderedDescending:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#endif // wxUSE_INTL
|
#endif // wxUSE_INTL
|
||||||
|
@@ -54,6 +54,26 @@ private:
|
|||||||
// implementation
|
// implementation
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
|
wxString wxLocaleIdent::GetName() const
|
||||||
|
{
|
||||||
|
// Construct name in the standard Unix format:
|
||||||
|
// language[_territory][.codeset][@modifier]
|
||||||
|
|
||||||
|
wxString name;
|
||||||
|
if ( !m_language.empty() )
|
||||||
|
{
|
||||||
|
name << m_language;
|
||||||
|
|
||||||
|
if ( !m_region.empty() )
|
||||||
|
name << "_" << m_region;
|
||||||
|
|
||||||
|
if ( !m_modifier.empty() )
|
||||||
|
name << "@" << m_modifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
// Helper of wxSetlocaleTryAll() below which tries setting the given locale
|
// Helper of wxSetlocaleTryAll() below which tries setting the given locale
|
||||||
// with and without UTF-8 suffix. Don't use this one directly.
|
// with and without UTF-8 suffix. Don't use this one directly.
|
||||||
static const char *wxSetlocaleTryUTF8(int c, const wxString& lc)
|
static const char *wxSetlocaleTryUTF8(int c, const wxString& lc)
|
||||||
|
Reference in New Issue
Block a user