Give QLocale's name() and bcp47Name() separator parameters

Previously name() has always used underscore and bcp47Name() dash; let
the user chose which one best fits their needs.

[ChangeLog][QtCore][QLocale] QLocale's name() and bcp47Name() now let
the caller chose what separator to use between the tags making up the
name, where there is more than one.

Change-Id: Ia689e6a3fb581b42905e7fb1ae7a7b688244d267
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Edward Welbourne 2023-08-08 17:34:10 +02:00
parent 820eff05f4
commit 15cfdab514
4 changed files with 72 additions and 16 deletions

View File

@ -625,6 +625,16 @@ QStringList QLocale::uiLanguages() const
return uiLanguages(TagSeparator::Dash);
}
QString QLocale::name() const
{
return name(TagSeparator::Underscore);
}
QString QLocale::bcp47Name() const
{
return bcp47Name(TagSeparator::Dash);
}
#include "qurl.h"
QUrl QUrl::fromEncoded(const QByteArray &input, ParsingMode mode)

View File

@ -705,7 +705,7 @@ static QLocalePrivate *c_private()
system locale. This is only intended as a way to let a platform plugin
install its own system locale, overriding what might otherwise be provided
for its class of platform (as Android does, differing from Linux), and to
let tests transiently over-ride the system or plugin-supplied one. As such,
let tests transiently override the system or plugin-supplied one. As such,
there should not be diverse threads creating and destroying QSystemLocale
instances concurrently, so no attempt is made at thread-safety in managing
the stack.
@ -1367,6 +1367,12 @@ QLocale::Country QLocale::country() const
with an arbitrary Unicode character or string.
*/
Q_DECL_COLD_FUNCTION static void badSeparatorWarning(const char *method, char sep)
{
qWarning("QLocale::%s(): Using non-ASCII separator '%c' (%02x) is unsupported",
method, sep, uint(uchar(sep)));
}
/*!
\brief The short name of this locale.
@ -1385,8 +1391,13 @@ QLocale::Country QLocale::country() const
\sa QLocale(), language(), script(), territory(), bcp47Name(), uiLanguages()
*/
QString QLocale::name() const
QString QLocale::name(TagSeparator separator) const
{
const char sep = char(separator);
if (uchar(sep) > 0x7f) {
badSeparatorWarning("name", sep);
return {};
}
const auto code = d->languageCode();
QLatin1StringView view{code.data()};
@ -1398,7 +1409,7 @@ QString QLocale::name() const
if (c == AnyTerritory)
return view;
return view + u'_' + d->territoryCode();
return view + QLatin1Char(sep) + d->territoryCode();
}
template <typename T> static inline
@ -1442,13 +1453,22 @@ T toIntegral_helper(const QLocalePrivate *d, QStringView str, bool *ok)
locale name of the QLocale data; this need not be the language the
user-interface should be in.
This function tries to conform the locale name to BCP47.
This function tries to conform the locale name to the IETF Best Common
Practice 47, defined by RFC 5646. It supports an optional \a separator
parameter which can be used to override the BCP47-specified use of a hyphen
to separate the tags. For use in IETF-defined protocols, however, the
default, QLocale::TagSeparator::Dash, should be retained.
\sa name(), language(), territory(), script(), uiLanguages()
*/
QString QLocale::bcp47Name() const
QString QLocale::bcp47Name(TagSeparator separator) const
{
return QString::fromLatin1(d->bcp47Name());
const char sep = char(separator);
if (uchar(sep) > 0x7f) {
badSeparatorWarning("bcp47Name", sep);
return {};
}
return QString::fromLatin1(d->bcp47Name(sep));
}
/*!
@ -4652,8 +4672,7 @@ QStringList QLocale::uiLanguages(TagSeparator separator) const
const char sep = char(separator);
QStringList uiLanguages;
if (uchar(sep) > 0x7f) {
qWarning("QLocale::uiLanguages(): Using non-ASCII separator '%c' (%02x) is unsupported",
sep, uint(uchar(sep)));
badSeparatorWarning("uiLanguages", sep);
return uiLanguages;
}
QList<QLocaleId> localeIds;
@ -4674,7 +4693,7 @@ QStringList QLocale::uiLanguages(TagSeparator separator) const
// first. (Known issue, QTBUG-104930, on some macOS versions when in
// locale en_DE.) Our translation system might have a translation for a
// locale the platform doesn't believe in.
const QString name = QString::fromLatin1(d->bcp47Name(sep));
const QString name = bcp47Name(separator);
if (!name.isEmpty() && language() != C && !uiLanguages.contains(name)) {
// That uses contains(name) as a cheap pre-test, but there may be an
// entry that matches this on purging likely subtags.

View File

@ -926,9 +926,14 @@ public:
QT_DEPRECATED_VERSION_X_6_6("Use territory() instead")
Country country() const;
#endif
QString name() const;
#if QT_CORE_REMOVED_SINCE(6, 7)
QString name() const;
QString bcp47Name() const;
#endif
QString name(TagSeparator separator = TagSeparator::Underscore) const;
QString bcp47Name(TagSeparator separator = TagSeparator::Dash) const;
QString nativeLanguageName() const;
QString nativeTerritoryName() const;
#if QT_DEPRECATED_SINCE(6, 6)

View File

@ -770,14 +770,24 @@ void tst_QLocale::unixLocaleName_data()
void tst_QLocale::unixLocaleName()
{
QFETCH(QLocale::Language, lang);
QFETCH(QLocale::Territory, land);
QFETCH(QString, expect);
QFETCH(const QLocale::Language, lang);
QFETCH(const QLocale::Territory, land);
QFETCH(const QString, expect);
const auto expected = [expect](QChar ch) {
// Kludge around QString::replace() not being const.
QString copy = expect;
return copy.replace(u'_', ch);
};
QLocale::setDefault(QLocale(QLocale::C));
QLocale locale(lang, land);
const QLocale locale(lang, land);
QCOMPARE(locale.name(), expect);
QCOMPARE(locale.name(QLocale::TagSeparator::Dash), expected(u'-'));
QCOMPARE(locale.name(QLocale::TagSeparator{'|'}), expected(u'|'));
QTest::ignoreMessage(QtWarningMsg, "QLocale::name(): "
"Using non-ASCII separator '\u00ff' (ff) is unsupported");
QCOMPARE(locale.name(QLocale::TagSeparator{'\xff'}), QString());
}
void tst_QLocale::toReal_data()
@ -3923,8 +3933,20 @@ void tst_QLocale::bcp47Name_data()
void tst_QLocale::bcp47Name()
{
QFETCH(QString, expect);
QCOMPARE(QLocale(QLatin1String(QTest::currentDataTag())).bcp47Name(), expect);
QFETCH(const QString, expect);
const auto expected = [expect](QChar ch) {
// Kludge around QString::replace() not being const.
QString copy = expect;
return copy.replace(u'-', ch);
};
const auto locale = QLocale(QLatin1String(QTest::currentDataTag()));
QCOMPARE(locale.bcp47Name(), expect);
QCOMPARE(locale.bcp47Name(QLocale::TagSeparator::Underscore), expected(u'_'));
QCOMPARE(locale.bcp47Name(QLocale::TagSeparator{'|'}), expected(u'|'));
QTest::ignoreMessage(QtWarningMsg, "QLocale::bcp47Name(): "
"Using non-ASCII separator '\u00ff' (ff) is unsupported");
QCOMPARE(locale.bcp47Name(QLocale::TagSeparator{'\xff'}), QString());
}
#ifndef QT_NO_SYSTEMLOCALE