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:
parent
9f43ec03e6
commit
c8269210a2
@ -108,6 +108,63 @@ struct WXDLLIMPEXP_BASE wxLanguageInfo
|
||||
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 // _WX_LOCALEDEFS_H_
|
||||
|
@ -45,6 +45,10 @@ public:
|
||||
wxString GetInfo(wxLocaleInfo index,
|
||||
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
|
||||
// its dtor is not virtual.
|
||||
~wxUILocale();
|
||||
|
@ -80,6 +80,24 @@ public:
|
||||
*/
|
||||
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.
|
||||
|
||||
@ -119,3 +137,93 @@ public:
|
||||
@since 3.1.6
|
||||
*/
|
||||
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
|
||||
|
||||
#include "wx/uilocale.h"
|
||||
#include "wx/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
|
||||
|
||||
void wxUseLCID(LCID lcid)
|
||||
@ -64,6 +102,34 @@ void wxUseLCID(LCID 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
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -138,4 +204,30 @@ wxUILocaleImpl* wxUILocaleImpl::CreateForLanguage(const wxLanguageInfo& info)
|
||||
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
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
#if wxUSE_INTL
|
||||
|
||||
#include "wx/uilocale.h"
|
||||
#include "wx/private/uilocale.h"
|
||||
|
||||
#include "wx/osx/core/cfref.h"
|
||||
@ -28,9 +29,40 @@
|
||||
#include <CoreFoundation/CFLocale.h>
|
||||
#include <CoreFoundation/CFString.h>
|
||||
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSLocale.h>
|
||||
|
||||
extern wxString
|
||||
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
|
||||
{
|
||||
|
||||
@ -100,4 +132,34 @@ wxUILocaleImpl* wxUILocaleImpl::CreateForLanguage(const wxLanguageInfo& info)
|
||||
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
|
||||
|
@ -54,6 +54,26 @@ private:
|
||||
// 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
|
||||
// with and without UTF-8 suffix. Don't use this one directly.
|
||||
static const char *wxSetlocaleTryUTF8(int c, const wxString& lc)
|
||||
|
Loading…
Reference in New Issue
Block a user