Advance Wayland and KDE package bring-up
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
# SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
add_subdirectory(i18n)
|
||||
add_subdirectory(localedata)
|
||||
if (TARGET Qt6::Qml)
|
||||
# add_subdirectory(i18n-qml)
|
||||
# add_subdirectory(localedata-qml)
|
||||
endif()
|
||||
|
||||
ecm_qt_install_logging_categories(
|
||||
EXPORT KI18N
|
||||
FILE ki18n.categories
|
||||
DESTINATION ${KDE_INSTALL_LOGGINGCATEGORIESDIR}
|
||||
)
|
||||
@@ -0,0 +1,61 @@
|
||||
# SPDX-FileCopyrightText: 2024 Volker Krause <vkrause@kde.org>
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
add_library(KF6I18nQml)
|
||||
add_library(KF6::I18nQml ALIAS KF6I18nQml)
|
||||
|
||||
set_target_properties(KF6I18nQml PROPERTIES
|
||||
VERSION ${KI18N_VERSION}
|
||||
SOVERSION ${KI18N_SOVERSION}
|
||||
EXPORT_NAME I18nQml
|
||||
)
|
||||
|
||||
target_sources(KF6I18nQml PRIVATE
|
||||
klocalizedqmlcontext.cpp
|
||||
)
|
||||
|
||||
ecm_qt_declare_logging_category(KF6I18nQml
|
||||
HEADER ki18n_qml_logging.h
|
||||
IDENTIFIER KI18N
|
||||
CATEGORY_NAME kf.i18n.qml
|
||||
DESCRIPTION "KI18n QML Integration"
|
||||
EXPORT KI18N
|
||||
)
|
||||
|
||||
ecm_generate_export_header(KF6I18nQml
|
||||
BASE_NAME KI18nQml
|
||||
GROUP_BASE_NAME KF
|
||||
VERSION ${KF_VERSION}
|
||||
USE_VERSION_HEADER
|
||||
VERSION_BASE_NAME KI18n
|
||||
DEPRECATED_BASE_VERSION 0
|
||||
DEPRECATION_VERSIONS
|
||||
EXCLUDE_DEPRECATED_BEFORE_AND_AT ${EXCLUDE_DEPRECATED_BEFORE_AND_AT}
|
||||
)
|
||||
|
||||
target_include_directories(KF6I18nQml
|
||||
INTERFACE "$<INSTALL_INTERFACE:${KDE_INSTALL_INCLUDEDIR_KF}/KI18n>"
|
||||
PUBLIC "$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}>" # for version header
|
||||
)
|
||||
|
||||
target_link_libraries(KF6I18nQml
|
||||
PUBLIC
|
||||
Qt6::Core
|
||||
PRIVATE
|
||||
KF6I18n
|
||||
Qt6::Qml
|
||||
)
|
||||
|
||||
ecm_generate_headers(KI18n_HEADERS
|
||||
HEADER_NAMES
|
||||
KLocalizedQmlContext
|
||||
REQUIRED_HEADERS KI18n_HEADERS
|
||||
)
|
||||
|
||||
install(TARGETS KF6I18nQml EXPORT KF6I18nTargets ${KF_INSTALL_TARGETS_DEFAULT_ARGS})
|
||||
|
||||
install(FILES
|
||||
${KI18n_HEADERS}
|
||||
${CMAKE_CURRENT_BINARY_DIR}/ki18nqml_export.h
|
||||
DESTINATION "${KDE_INSTALL_INCLUDEDIR_KF}/KI18n" COMPONENT Devel
|
||||
)
|
||||
@@ -0,0 +1,634 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
// Undefine this because we don't want our i18n*() method names to be turned into i18nd*()
|
||||
#undef TRANSLATION_DOMAIN
|
||||
|
||||
#include "klocalizedqmlcontext.h"
|
||||
|
||||
#include <klocalizedstring.h>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QQmlContext>
|
||||
#include <QQmlEngine>
|
||||
|
||||
#include "ki18n_qml_logging.h"
|
||||
|
||||
class KLocalizedQmlContextPrivate
|
||||
{
|
||||
public:
|
||||
void markCurrentFunctionAsTranslationBinding(const KLocalizedQmlContext *q) const;
|
||||
|
||||
QString m_translationDomain;
|
||||
};
|
||||
|
||||
void KLocalizedQmlContextPrivate::markCurrentFunctionAsTranslationBinding(const KLocalizedQmlContext *q) const
|
||||
{
|
||||
#if QT_VERSION > QT_VERSION_CHECK(6, 6, 0)
|
||||
if (auto engine = qmlEngine(q); engine) {
|
||||
engine->markCurrentFunctionAsTranslationBinding();
|
||||
} else {
|
||||
qCDebug(KI18N) << "No QML engine available, KLocalizedQmlContext not properly set up?";
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
KLocalizedQmlContext::KLocalizedQmlContext(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new KLocalizedQmlContextPrivate)
|
||||
{
|
||||
QCoreApplication::instance()->installEventFilter(this);
|
||||
}
|
||||
|
||||
KLocalizedQmlContext::~KLocalizedQmlContext() = default;
|
||||
|
||||
QString KLocalizedQmlContext::translationDomain() const
|
||||
{
|
||||
return d->m_translationDomain;
|
||||
}
|
||||
|
||||
void KLocalizedQmlContext::setTranslationDomain(const QString &domain)
|
||||
{
|
||||
if (domain != d->m_translationDomain) {
|
||||
d->m_translationDomain = domain;
|
||||
Q_EMIT translationDomainChanged(domain);
|
||||
}
|
||||
}
|
||||
|
||||
static void subsVariant(KLocalizedString &trMessage, const QVariant &value)
|
||||
{
|
||||
switch (value.userType()) {
|
||||
case QMetaType::QString:
|
||||
trMessage = trMessage.subs(value.toString());
|
||||
break;
|
||||
case QMetaType::Int:
|
||||
trMessage = trMessage.subs(value.toInt());
|
||||
break;
|
||||
case QMetaType::Double:
|
||||
trMessage = trMessage.subs(value.toDouble());
|
||||
break;
|
||||
case QMetaType::Char:
|
||||
trMessage = trMessage.subs(value.toChar());
|
||||
break;
|
||||
default:
|
||||
if (value.canConvert<QString>()) {
|
||||
trMessage = trMessage.subs(value.toString());
|
||||
} else {
|
||||
trMessage = trMessage.subs(QStringLiteral("???"));
|
||||
qCWarning(KI18N) << "couldn't convert" << value << "to translate";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void resolveMessage(KLocalizedString &trMessage,
|
||||
const QVariant ¶m1,
|
||||
const QVariant ¶m2,
|
||||
const QVariant ¶m3,
|
||||
const QVariant ¶m4,
|
||||
const QVariant ¶m5,
|
||||
const QVariant ¶m6,
|
||||
const QVariant ¶m7,
|
||||
const QVariant ¶m8,
|
||||
const QVariant ¶m9,
|
||||
const QVariant ¶m10 = QVariant())
|
||||
{
|
||||
if (param1.isValid()) {
|
||||
subsVariant(trMessage, param1);
|
||||
}
|
||||
if (param2.isValid()) {
|
||||
subsVariant(trMessage, param2);
|
||||
}
|
||||
if (param3.isValid()) {
|
||||
subsVariant(trMessage, param3);
|
||||
}
|
||||
if (param4.isValid()) {
|
||||
subsVariant(trMessage, param4);
|
||||
}
|
||||
if (param5.isValid()) {
|
||||
subsVariant(trMessage, param5);
|
||||
}
|
||||
if (param6.isValid()) {
|
||||
subsVariant(trMessage, param6);
|
||||
}
|
||||
if (param7.isValid()) {
|
||||
subsVariant(trMessage, param7);
|
||||
}
|
||||
if (param8.isValid()) {
|
||||
subsVariant(trMessage, param8);
|
||||
}
|
||||
if (param9.isValid()) {
|
||||
subsVariant(trMessage, param9);
|
||||
}
|
||||
if (param10.isValid()) {
|
||||
subsVariant(trMessage, param10);
|
||||
}
|
||||
}
|
||||
|
||||
static void resolvePlural(KLocalizedString &trMessage, const QVariant ¶m)
|
||||
{
|
||||
trMessage = trMessage.subs(param.toInt());
|
||||
}
|
||||
|
||||
QString KLocalizedQmlContext::i18n(const QString &message,
|
||||
const QVariant ¶m1,
|
||||
const QVariant ¶m2,
|
||||
const QVariant ¶m3,
|
||||
const QVariant ¶m4,
|
||||
const QVariant ¶m5,
|
||||
const QVariant ¶m6,
|
||||
const QVariant ¶m7,
|
||||
const QVariant ¶m8,
|
||||
const QVariant ¶m9,
|
||||
const QVariant ¶m10) const
|
||||
{
|
||||
if (message.isEmpty()) {
|
||||
qCWarning(KI18N) << "i18n() needs at least one parameter";
|
||||
return QString();
|
||||
}
|
||||
|
||||
KLocalizedString trMessage;
|
||||
if (!d->m_translationDomain.isEmpty()) {
|
||||
trMessage = ki18nd(d->m_translationDomain.toUtf8().constData(), message.toUtf8().constData());
|
||||
} else {
|
||||
trMessage = ki18n(message.toUtf8().constData());
|
||||
}
|
||||
|
||||
resolveMessage(trMessage, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10);
|
||||
|
||||
d->markCurrentFunctionAsTranslationBinding(this);
|
||||
return trMessage.toString();
|
||||
}
|
||||
|
||||
QString KLocalizedQmlContext::i18nc(const QString &context,
|
||||
const QString &message,
|
||||
const QVariant ¶m1,
|
||||
const QVariant ¶m2,
|
||||
const QVariant ¶m3,
|
||||
const QVariant ¶m4,
|
||||
const QVariant ¶m5,
|
||||
const QVariant ¶m6,
|
||||
const QVariant ¶m7,
|
||||
const QVariant ¶m8,
|
||||
const QVariant ¶m9,
|
||||
const QVariant ¶m10) const
|
||||
{
|
||||
if (context.isEmpty() || message.isEmpty()) {
|
||||
qCWarning(KI18N).noquote().nospace() << "i18nc(\"" << context << message << "\") needs at least two arguments";
|
||||
return QString();
|
||||
}
|
||||
|
||||
KLocalizedString trMessage;
|
||||
if (!d->m_translationDomain.isEmpty()) {
|
||||
trMessage = ki18ndc(d->m_translationDomain.toUtf8().constData(), context.toUtf8().constData(), message.toUtf8().constData());
|
||||
} else {
|
||||
trMessage = ki18nc(context.toUtf8().constData(), message.toUtf8().constData());
|
||||
}
|
||||
|
||||
resolveMessage(trMessage, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10);
|
||||
|
||||
d->markCurrentFunctionAsTranslationBinding(this);
|
||||
return trMessage.toString();
|
||||
}
|
||||
|
||||
QString KLocalizedQmlContext::i18np(const QString &singular,
|
||||
const QString &plural,
|
||||
const QVariant ¶m1,
|
||||
const QVariant ¶m2,
|
||||
const QVariant ¶m3,
|
||||
const QVariant ¶m4,
|
||||
const QVariant ¶m5,
|
||||
const QVariant ¶m6,
|
||||
const QVariant ¶m7,
|
||||
const QVariant ¶m8,
|
||||
const QVariant ¶m9,
|
||||
const QVariant ¶m10) const
|
||||
{
|
||||
if (singular.isEmpty() || plural.isEmpty()) {
|
||||
qCWarning(KI18N).noquote().nospace() << "i18np(\"" << singular << plural << "\") needs at least two arguments";
|
||||
return QString();
|
||||
}
|
||||
|
||||
KLocalizedString trMessage;
|
||||
if (!d->m_translationDomain.isEmpty()) {
|
||||
trMessage = ki18ndp(d->m_translationDomain.toUtf8().constData(), singular.toUtf8().constData(), plural.toUtf8().constData());
|
||||
} else {
|
||||
trMessage = ki18np(singular.toUtf8().constData(), plural.toUtf8().constData());
|
||||
}
|
||||
|
||||
resolvePlural(trMessage, param1);
|
||||
resolveMessage(trMessage, param2, param3, param4, param5, param6, param7, param8, param9, param10);
|
||||
|
||||
d->markCurrentFunctionAsTranslationBinding(this);
|
||||
return trMessage.toString();
|
||||
}
|
||||
|
||||
QString KLocalizedQmlContext::i18ncp(const QString &context,
|
||||
const QString &singular,
|
||||
const QString &plural,
|
||||
const QVariant ¶m1,
|
||||
const QVariant ¶m2,
|
||||
const QVariant ¶m3,
|
||||
const QVariant ¶m4,
|
||||
const QVariant ¶m5,
|
||||
const QVariant ¶m6,
|
||||
const QVariant ¶m7,
|
||||
const QVariant ¶m8,
|
||||
const QVariant ¶m9,
|
||||
const QVariant ¶m10) const
|
||||
{
|
||||
if (context.isEmpty() || singular.isEmpty() || plural.isEmpty()) {
|
||||
qCWarning(KI18N) << "i18ncp() needs at least three arguments";
|
||||
return QString();
|
||||
}
|
||||
|
||||
KLocalizedString trMessage;
|
||||
if (!d->m_translationDomain.isEmpty()) {
|
||||
trMessage =
|
||||
ki18ndcp(d->m_translationDomain.toUtf8().constData(), context.toUtf8().constData(), singular.toUtf8().constData(), plural.toUtf8().constData());
|
||||
} else {
|
||||
trMessage = ki18ncp(context.toUtf8().constData(), singular.toUtf8().constData(), plural.toUtf8().constData());
|
||||
}
|
||||
|
||||
resolvePlural(trMessage, param1);
|
||||
resolveMessage(trMessage, param2, param3, param4, param5, param6, param7, param8, param9, param10);
|
||||
|
||||
d->markCurrentFunctionAsTranslationBinding(this);
|
||||
return trMessage.toString();
|
||||
}
|
||||
|
||||
QString KLocalizedQmlContext::i18nd(const QString &domain,
|
||||
const QString &message,
|
||||
const QVariant ¶m1,
|
||||
const QVariant ¶m2,
|
||||
const QVariant ¶m3,
|
||||
const QVariant ¶m4,
|
||||
const QVariant ¶m5,
|
||||
const QVariant ¶m6,
|
||||
const QVariant ¶m7,
|
||||
const QVariant ¶m8,
|
||||
const QVariant ¶m9,
|
||||
const QVariant ¶m10) const
|
||||
{
|
||||
if (domain.isEmpty() || message.isEmpty()) {
|
||||
qCWarning(KI18N).noquote().nospace() << "i18nd(\"" << domain << message << "\") needs at least two parameters";
|
||||
return QString();
|
||||
}
|
||||
|
||||
KLocalizedString trMessage = ki18nd(domain.toUtf8().constData(), message.toUtf8().constData());
|
||||
|
||||
resolveMessage(trMessage, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10);
|
||||
|
||||
d->markCurrentFunctionAsTranslationBinding(this);
|
||||
return trMessage.toString();
|
||||
}
|
||||
|
||||
QString KLocalizedQmlContext::i18ndc(const QString &domain,
|
||||
const QString &context,
|
||||
const QString &message,
|
||||
const QVariant ¶m1,
|
||||
const QVariant ¶m2,
|
||||
const QVariant ¶m3,
|
||||
const QVariant ¶m4,
|
||||
const QVariant ¶m5,
|
||||
const QVariant ¶m6,
|
||||
const QVariant ¶m7,
|
||||
const QVariant ¶m8,
|
||||
const QVariant ¶m9,
|
||||
const QVariant ¶m10) const
|
||||
{
|
||||
if (domain.isEmpty() || context.isEmpty() || message.isEmpty()) {
|
||||
qCWarning(KI18N) << "i18ndc() needs at least three arguments";
|
||||
return QString();
|
||||
}
|
||||
|
||||
KLocalizedString trMessage = ki18ndc(domain.toUtf8().constData(), context.toUtf8().constData(), message.toUtf8().constData());
|
||||
|
||||
resolveMessage(trMessage, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10);
|
||||
|
||||
d->markCurrentFunctionAsTranslationBinding(this);
|
||||
return trMessage.toString();
|
||||
}
|
||||
|
||||
QString KLocalizedQmlContext::i18ndp(const QString &domain,
|
||||
const QString &singular,
|
||||
const QString &plural,
|
||||
const QVariant ¶m1,
|
||||
const QVariant ¶m2,
|
||||
const QVariant ¶m3,
|
||||
const QVariant ¶m4,
|
||||
const QVariant ¶m5,
|
||||
const QVariant ¶m6,
|
||||
const QVariant ¶m7,
|
||||
const QVariant ¶m8,
|
||||
const QVariant ¶m9,
|
||||
const QVariant ¶m10) const
|
||||
{
|
||||
if (domain.isEmpty() || singular.isEmpty() || plural.isEmpty()) {
|
||||
qCWarning(KI18N) << "i18ndp() needs at least three arguments";
|
||||
return QString();
|
||||
}
|
||||
|
||||
KLocalizedString trMessage = ki18ndp(domain.toUtf8().constData(), singular.toUtf8().constData(), plural.toUtf8().constData());
|
||||
|
||||
resolvePlural(trMessage, param1);
|
||||
resolveMessage(trMessage, param2, param3, param4, param5, param6, param7, param8, param9, param10);
|
||||
|
||||
d->markCurrentFunctionAsTranslationBinding(this);
|
||||
return trMessage.toString();
|
||||
}
|
||||
|
||||
QString KLocalizedQmlContext::i18ndcp(const QString &domain,
|
||||
const QString &context,
|
||||
const QString &singular,
|
||||
const QString &plural,
|
||||
const QVariant ¶m1,
|
||||
const QVariant ¶m2,
|
||||
const QVariant ¶m3,
|
||||
const QVariant ¶m4,
|
||||
const QVariant ¶m5,
|
||||
const QVariant ¶m6,
|
||||
const QVariant ¶m7,
|
||||
const QVariant ¶m8,
|
||||
const QVariant ¶m9,
|
||||
const QVariant ¶m10) const
|
||||
{
|
||||
if (domain.isEmpty() || context.isEmpty() || singular.isEmpty() || plural.isEmpty()) {
|
||||
qCWarning(KI18N) << "i18ndcp() needs at least four arguments";
|
||||
return QString();
|
||||
}
|
||||
|
||||
KLocalizedString trMessage =
|
||||
ki18ndcp(domain.toUtf8().constData(), context.toUtf8().constData(), singular.toUtf8().constData(), plural.toUtf8().constData());
|
||||
|
||||
resolvePlural(trMessage, param1);
|
||||
resolveMessage(trMessage, param2, param3, param4, param5, param6, param7, param8, param9, param10);
|
||||
|
||||
d->markCurrentFunctionAsTranslationBinding(this);
|
||||
return trMessage.toString();
|
||||
}
|
||||
|
||||
/////////////////////////
|
||||
|
||||
QString KLocalizedQmlContext::xi18n(const QString &message,
|
||||
const QVariant ¶m1,
|
||||
const QVariant ¶m2,
|
||||
const QVariant ¶m3,
|
||||
const QVariant ¶m4,
|
||||
const QVariant ¶m5,
|
||||
const QVariant ¶m6,
|
||||
const QVariant ¶m7,
|
||||
const QVariant ¶m8,
|
||||
const QVariant ¶m9,
|
||||
const QVariant ¶m10) const
|
||||
{
|
||||
if (message.isEmpty()) {
|
||||
qCWarning(KI18N) << "xi18n() needs at least one parameter";
|
||||
return QString();
|
||||
}
|
||||
|
||||
KLocalizedString trMessage;
|
||||
if (!d->m_translationDomain.isEmpty()) {
|
||||
trMessage = kxi18nd(d->m_translationDomain.toUtf8().constData(), message.toUtf8().constData());
|
||||
} else {
|
||||
trMessage = kxi18n(message.toUtf8().constData());
|
||||
}
|
||||
|
||||
resolveMessage(trMessage, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10);
|
||||
|
||||
d->markCurrentFunctionAsTranslationBinding(this);
|
||||
return trMessage.toString();
|
||||
}
|
||||
|
||||
QString KLocalizedQmlContext::xi18nc(const QString &context,
|
||||
const QString &message,
|
||||
const QVariant ¶m1,
|
||||
const QVariant ¶m2,
|
||||
const QVariant ¶m3,
|
||||
const QVariant ¶m4,
|
||||
const QVariant ¶m5,
|
||||
const QVariant ¶m6,
|
||||
const QVariant ¶m7,
|
||||
const QVariant ¶m8,
|
||||
const QVariant ¶m9,
|
||||
const QVariant ¶m10) const
|
||||
{
|
||||
if (context.isEmpty() || message.isEmpty()) {
|
||||
qCWarning(KI18N).noquote().nospace() << "xi18nc(\"" << context << message << "\") needs at least two arguments";
|
||||
return QString();
|
||||
}
|
||||
|
||||
KLocalizedString trMessage;
|
||||
if (!d->m_translationDomain.isEmpty()) {
|
||||
trMessage = kxi18ndc(d->m_translationDomain.toUtf8().constData(), context.toUtf8().constData(), message.toUtf8().constData());
|
||||
} else {
|
||||
trMessage = kxi18nc(context.toUtf8().constData(), message.toUtf8().constData());
|
||||
}
|
||||
|
||||
resolveMessage(trMessage, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10);
|
||||
|
||||
d->markCurrentFunctionAsTranslationBinding(this);
|
||||
return trMessage.toString();
|
||||
}
|
||||
|
||||
QString KLocalizedQmlContext::xi18np(const QString &singular,
|
||||
const QString &plural,
|
||||
const QVariant ¶m1,
|
||||
const QVariant ¶m2,
|
||||
const QVariant ¶m3,
|
||||
const QVariant ¶m4,
|
||||
const QVariant ¶m5,
|
||||
const QVariant ¶m6,
|
||||
const QVariant ¶m7,
|
||||
const QVariant ¶m8,
|
||||
const QVariant ¶m9,
|
||||
const QVariant ¶m10) const
|
||||
{
|
||||
if (singular.isEmpty() || plural.isEmpty()) {
|
||||
qCWarning(KI18N).noquote().nospace() << "xi18np(\"" << singular << plural << "\") needs at least two arguments";
|
||||
return QString();
|
||||
}
|
||||
|
||||
KLocalizedString trMessage;
|
||||
if (!d->m_translationDomain.isEmpty()) {
|
||||
trMessage = kxi18ndp(d->m_translationDomain.toUtf8().constData(), singular.toUtf8().constData(), plural.toUtf8().constData());
|
||||
} else {
|
||||
trMessage = kxi18np(singular.toUtf8().constData(), plural.toUtf8().constData());
|
||||
}
|
||||
|
||||
resolvePlural(trMessage, param1);
|
||||
resolveMessage(trMessage, param2, param3, param4, param5, param6, param7, param8, param9, param10);
|
||||
|
||||
d->markCurrentFunctionAsTranslationBinding(this);
|
||||
return trMessage.toString();
|
||||
}
|
||||
|
||||
QString KLocalizedQmlContext::xi18ncp(const QString &context,
|
||||
const QString &singular,
|
||||
const QString &plural,
|
||||
const QVariant ¶m1,
|
||||
const QVariant ¶m2,
|
||||
const QVariant ¶m3,
|
||||
const QVariant ¶m4,
|
||||
const QVariant ¶m5,
|
||||
const QVariant ¶m6,
|
||||
const QVariant ¶m7,
|
||||
const QVariant ¶m8,
|
||||
const QVariant ¶m9,
|
||||
const QVariant ¶m10) const
|
||||
{
|
||||
if (context.isEmpty() || singular.isEmpty() || plural.isEmpty()) {
|
||||
qCWarning(KI18N) << "xi18ncp() needs at least three arguments";
|
||||
return QString();
|
||||
}
|
||||
|
||||
KLocalizedString trMessage;
|
||||
if (!d->m_translationDomain.isEmpty()) {
|
||||
trMessage =
|
||||
kxi18ndcp(d->m_translationDomain.toUtf8().constData(), context.toUtf8().constData(), singular.toUtf8().constData(), plural.toUtf8().constData());
|
||||
} else {
|
||||
trMessage = kxi18ncp(context.toUtf8().constData(), singular.toUtf8().constData(), plural.toUtf8().constData());
|
||||
}
|
||||
|
||||
resolvePlural(trMessage, param1);
|
||||
resolveMessage(trMessage, param2, param3, param4, param5, param6, param7, param8, param9, param10);
|
||||
|
||||
d->markCurrentFunctionAsTranslationBinding(this);
|
||||
return trMessage.toString();
|
||||
}
|
||||
|
||||
QString KLocalizedQmlContext::xi18nd(const QString &domain,
|
||||
const QString &message,
|
||||
const QVariant ¶m1,
|
||||
const QVariant ¶m2,
|
||||
const QVariant ¶m3,
|
||||
const QVariant ¶m4,
|
||||
const QVariant ¶m5,
|
||||
const QVariant ¶m6,
|
||||
const QVariant ¶m7,
|
||||
const QVariant ¶m8,
|
||||
const QVariant ¶m9,
|
||||
const QVariant ¶m10) const
|
||||
{
|
||||
if (domain.isEmpty() || message.isEmpty()) {
|
||||
qCWarning(KI18N).noquote().nospace() << "xi18nd(\"" << domain << message << "\") needs at least two parameters";
|
||||
return QString();
|
||||
}
|
||||
|
||||
KLocalizedString trMessage = kxi18nd(domain.toUtf8().constData(), message.toUtf8().constData());
|
||||
|
||||
resolveMessage(trMessage, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10);
|
||||
|
||||
d->markCurrentFunctionAsTranslationBinding(this);
|
||||
return trMessage.toString();
|
||||
}
|
||||
|
||||
QString KLocalizedQmlContext::xi18ndc(const QString &domain,
|
||||
const QString &context,
|
||||
const QString &message,
|
||||
const QVariant ¶m1,
|
||||
const QVariant ¶m2,
|
||||
const QVariant ¶m3,
|
||||
const QVariant ¶m4,
|
||||
const QVariant ¶m5,
|
||||
const QVariant ¶m6,
|
||||
const QVariant ¶m7,
|
||||
const QVariant ¶m8,
|
||||
const QVariant ¶m9,
|
||||
const QVariant ¶m10) const
|
||||
{
|
||||
if (domain.isEmpty() || context.isEmpty() || message.isEmpty()) {
|
||||
qCWarning(KI18N) << "x18ndc() needs at least three arguments";
|
||||
return QString();
|
||||
}
|
||||
|
||||
KLocalizedString trMessage = kxi18ndc(domain.toUtf8().constData(), context.toUtf8().constData(), message.toUtf8().constData());
|
||||
|
||||
resolveMessage(trMessage, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10);
|
||||
|
||||
d->markCurrentFunctionAsTranslationBinding(this);
|
||||
return trMessage.toString();
|
||||
}
|
||||
|
||||
QString KLocalizedQmlContext::xi18ndp(const QString &domain,
|
||||
const QString &singular,
|
||||
const QString &plural,
|
||||
const QVariant ¶m1,
|
||||
const QVariant ¶m2,
|
||||
const QVariant ¶m3,
|
||||
const QVariant ¶m4,
|
||||
const QVariant ¶m5,
|
||||
const QVariant ¶m6,
|
||||
const QVariant ¶m7,
|
||||
const QVariant ¶m8,
|
||||
const QVariant ¶m9,
|
||||
const QVariant ¶m10) const
|
||||
{
|
||||
if (domain.isEmpty() || singular.isEmpty() || plural.isEmpty()) {
|
||||
qCWarning(KI18N) << "xi18ndp() needs at least three arguments";
|
||||
return QString();
|
||||
}
|
||||
|
||||
KLocalizedString trMessage = kxi18ndp(domain.toUtf8().constData(), singular.toUtf8().constData(), plural.toUtf8().constData());
|
||||
|
||||
resolvePlural(trMessage, param1);
|
||||
resolveMessage(trMessage, param2, param3, param4, param5, param6, param7, param8, param9, param10);
|
||||
|
||||
d->markCurrentFunctionAsTranslationBinding(this);
|
||||
return trMessage.toString();
|
||||
}
|
||||
|
||||
QString KLocalizedQmlContext::xi18ndcp(const QString &domain,
|
||||
const QString &context,
|
||||
const QString &singular,
|
||||
const QString &plural,
|
||||
const QVariant ¶m1,
|
||||
const QVariant ¶m2,
|
||||
const QVariant ¶m3,
|
||||
const QVariant ¶m4,
|
||||
const QVariant ¶m5,
|
||||
const QVariant ¶m6,
|
||||
const QVariant ¶m7,
|
||||
const QVariant ¶m8,
|
||||
const QVariant ¶m9,
|
||||
const QVariant ¶m10) const
|
||||
{
|
||||
if (domain.isEmpty() || context.isEmpty() || singular.isEmpty() || plural.isEmpty()) {
|
||||
qCWarning(KI18N) << "xi18ndcp() needs at least four arguments";
|
||||
return QString();
|
||||
}
|
||||
|
||||
KLocalizedString trMessage =
|
||||
kxi18ndcp(domain.toUtf8().constData(), context.toUtf8().constData(), singular.toUtf8().constData(), plural.toUtf8().constData());
|
||||
|
||||
resolvePlural(trMessage, param1);
|
||||
resolveMessage(trMessage, param2, param3, param4, param5, param6, param7, param8, param9, param10);
|
||||
|
||||
d->markCurrentFunctionAsTranslationBinding(this);
|
||||
return trMessage.toString();
|
||||
}
|
||||
|
||||
bool KLocalizedQmlContext::eventFilter(QObject *watched, QEvent *event)
|
||||
{
|
||||
if (event->type() == QEvent::LanguageChange && watched == QCoreApplication::instance()) {
|
||||
qCDebug(KI18N) << "triggering binding reevaluation";
|
||||
// run this deferred so we can be sure other things have reacted, such as KLocalizedString
|
||||
// having updated its internal caches
|
||||
if (auto engine = qmlEngine(this); engine) {
|
||||
QMetaObject::invokeMethod(engine, &QQmlEngine::retranslate, Qt::QueuedConnection);
|
||||
}
|
||||
}
|
||||
return QObject::eventFilter(watched, event);
|
||||
}
|
||||
|
||||
KLocalizedQmlContext *KLocalization::Internal::createLocalizedContext(QQmlEngine *engine)
|
||||
{
|
||||
auto ctx = new KLocalizedQmlContext(engine);
|
||||
engine->rootContext()->setContextObject(ctx);
|
||||
QQmlEngine::setContextForObject(ctx, engine->rootContext());
|
||||
return ctx;
|
||||
}
|
||||
|
||||
#include "moc_klocalizedqmlcontext.cpp"
|
||||
@@ -0,0 +1,326 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2011 Marco Martin <mart@kde.org>
|
||||
SPDX-FileCopyrightText: 2015 Aleix Pol Gonzalez <aleixpol@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef KLOCALIZEDQMLCONTEXT_H
|
||||
#define KLOCALIZEDQMLCONTEXT_H
|
||||
|
||||
#include <ki18nqml_export.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QVariant>
|
||||
#include <memory>
|
||||
|
||||
class QQmlEngine;
|
||||
|
||||
class KLocalizedQmlContextPrivate;
|
||||
|
||||
/**
|
||||
* @class KLocalizedQmlContext klocalizedcontext.h <KLocalizedQmlContext>
|
||||
*
|
||||
* This class is meant to be used to simplify integration of the KI18n framework
|
||||
* in QML.
|
||||
*
|
||||
* The way to do so, is by creating this object and setting it as a context
|
||||
* object:
|
||||
*
|
||||
* @code
|
||||
* QQmlApplicationEngine engine;
|
||||
* auto ctx = new KLocalizedQmlContext(&engine);
|
||||
* engine->rootContext()->setContextObject(ctx);
|
||||
* QQmlEngine::setContextForObject(ctx, engine.rootContext());
|
||||
* ctx->setTranslationDomain(...);
|
||||
* @endcode
|
||||
*
|
||||
* In many cases this can be simplified using KLocalization::setupLocalizedContext():
|
||||
* @code
|
||||
* QQmlApplicationEngine engine;
|
||||
* KLocalization::setupLocalizedContext(&engine);
|
||||
* @endcode
|
||||
*
|
||||
* Then i18n*() and xi18n*() functions should be available for use from the code
|
||||
* loaded in the engine, for the view.
|
||||
*
|
||||
* Unlike its predecessor KLocalizedContext this does automatically trigger
|
||||
* a binding re-evaluation when the application language is changed at runtime
|
||||
* (with Qt 6.6 or higher).
|
||||
*
|
||||
* @note Plural functions differ from the C/C++ version. On QML/JS we can get a
|
||||
* real value easily. To solve warnings on those cases we'll cast the first argument
|
||||
* to make sure it's taken into account for the plural.
|
||||
*
|
||||
* @since 6.8
|
||||
*/
|
||||
class KI18NQML_EXPORT KLocalizedQmlContext : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
/**
|
||||
* This property only needs to be specified if the context is being run on a library.
|
||||
* in an application there is no need to set the translation domain as the application's
|
||||
* domain can be used.
|
||||
*/
|
||||
Q_PROPERTY(QString translationDomain READ translationDomain WRITE setTranslationDomain NOTIFY translationDomainChanged)
|
||||
|
||||
public:
|
||||
explicit KLocalizedQmlContext(QObject *parent = nullptr);
|
||||
~KLocalizedQmlContext() override;
|
||||
|
||||
QString translationDomain() const;
|
||||
void setTranslationDomain(const QString &domain);
|
||||
|
||||
Q_INVOKABLE QString i18n(const QString &message,
|
||||
const QVariant ¶m1 = QVariant(),
|
||||
const QVariant ¶m2 = QVariant(),
|
||||
const QVariant ¶m3 = QVariant(),
|
||||
const QVariant ¶m4 = QVariant(),
|
||||
const QVariant ¶m5 = QVariant(),
|
||||
const QVariant ¶m6 = QVariant(),
|
||||
const QVariant ¶m7 = QVariant(),
|
||||
const QVariant ¶m8 = QVariant(),
|
||||
const QVariant ¶m9 = QVariant(),
|
||||
const QVariant ¶m10 = QVariant()) const;
|
||||
|
||||
Q_INVOKABLE QString i18nc(const QString &context,
|
||||
const QString &message,
|
||||
const QVariant ¶m1 = QVariant(),
|
||||
const QVariant ¶m2 = QVariant(),
|
||||
const QVariant ¶m3 = QVariant(),
|
||||
const QVariant ¶m4 = QVariant(),
|
||||
const QVariant ¶m5 = QVariant(),
|
||||
const QVariant ¶m6 = QVariant(),
|
||||
const QVariant ¶m7 = QVariant(),
|
||||
const QVariant ¶m8 = QVariant(),
|
||||
const QVariant ¶m9 = QVariant(),
|
||||
const QVariant ¶m10 = QVariant()) const;
|
||||
|
||||
Q_INVOKABLE QString i18np(const QString &singular,
|
||||
const QString &plural,
|
||||
const QVariant ¶m1 = QVariant(),
|
||||
const QVariant ¶m2 = QVariant(),
|
||||
const QVariant ¶m3 = QVariant(),
|
||||
const QVariant ¶m4 = QVariant(),
|
||||
const QVariant ¶m5 = QVariant(),
|
||||
const QVariant ¶m6 = QVariant(),
|
||||
const QVariant ¶m7 = QVariant(),
|
||||
const QVariant ¶m8 = QVariant(),
|
||||
const QVariant ¶m9 = QVariant(),
|
||||
const QVariant ¶m10 = QVariant()) const;
|
||||
|
||||
Q_INVOKABLE QString i18ncp(const QString &context,
|
||||
const QString &singular,
|
||||
const QString &plural,
|
||||
const QVariant ¶m1 = QVariant(),
|
||||
const QVariant ¶m2 = QVariant(),
|
||||
const QVariant ¶m3 = QVariant(),
|
||||
const QVariant ¶m4 = QVariant(),
|
||||
const QVariant ¶m5 = QVariant(),
|
||||
const QVariant ¶m6 = QVariant(),
|
||||
const QVariant ¶m7 = QVariant(),
|
||||
const QVariant ¶m8 = QVariant(),
|
||||
const QVariant ¶m9 = QVariant(),
|
||||
const QVariant ¶m10 = QVariant()) const;
|
||||
|
||||
Q_INVOKABLE QString i18nd(const QString &domain,
|
||||
const QString &message,
|
||||
const QVariant ¶m1 = QVariant(),
|
||||
const QVariant ¶m2 = QVariant(),
|
||||
const QVariant ¶m3 = QVariant(),
|
||||
const QVariant ¶m4 = QVariant(),
|
||||
const QVariant ¶m5 = QVariant(),
|
||||
const QVariant ¶m6 = QVariant(),
|
||||
const QVariant ¶m7 = QVariant(),
|
||||
const QVariant ¶m8 = QVariant(),
|
||||
const QVariant ¶m9 = QVariant(),
|
||||
const QVariant ¶m10 = QVariant()) const;
|
||||
|
||||
Q_INVOKABLE QString i18ndc(const QString &domain,
|
||||
const QString &context,
|
||||
const QString &message,
|
||||
const QVariant ¶m1 = QVariant(),
|
||||
const QVariant ¶m2 = QVariant(),
|
||||
const QVariant ¶m3 = QVariant(),
|
||||
const QVariant ¶m4 = QVariant(),
|
||||
const QVariant ¶m5 = QVariant(),
|
||||
const QVariant ¶m6 = QVariant(),
|
||||
const QVariant ¶m7 = QVariant(),
|
||||
const QVariant ¶m8 = QVariant(),
|
||||
const QVariant ¶m9 = QVariant(),
|
||||
const QVariant ¶m10 = QVariant()) const;
|
||||
|
||||
Q_INVOKABLE QString i18ndp(const QString &domain,
|
||||
const QString &singular,
|
||||
const QString &plural,
|
||||
const QVariant ¶m1 = QVariant(),
|
||||
const QVariant ¶m2 = QVariant(),
|
||||
const QVariant ¶m3 = QVariant(),
|
||||
const QVariant ¶m4 = QVariant(),
|
||||
const QVariant ¶m5 = QVariant(),
|
||||
const QVariant ¶m6 = QVariant(),
|
||||
const QVariant ¶m7 = QVariant(),
|
||||
const QVariant ¶m8 = QVariant(),
|
||||
const QVariant ¶m9 = QVariant(),
|
||||
const QVariant ¶m10 = QVariant()) const;
|
||||
|
||||
Q_INVOKABLE QString i18ndcp(const QString &domain,
|
||||
const QString &context,
|
||||
const QString &singular,
|
||||
const QString &plural,
|
||||
const QVariant ¶m1 = QVariant(),
|
||||
const QVariant ¶m2 = QVariant(),
|
||||
const QVariant ¶m3 = QVariant(),
|
||||
const QVariant ¶m4 = QVariant(),
|
||||
const QVariant ¶m5 = QVariant(),
|
||||
const QVariant ¶m6 = QVariant(),
|
||||
const QVariant ¶m7 = QVariant(),
|
||||
const QVariant ¶m8 = QVariant(),
|
||||
const QVariant ¶m9 = QVariant(),
|
||||
const QVariant ¶m10 = QVariant()) const;
|
||||
|
||||
Q_INVOKABLE QString xi18n(const QString &message,
|
||||
const QVariant ¶m1 = QVariant(),
|
||||
const QVariant ¶m2 = QVariant(),
|
||||
const QVariant ¶m3 = QVariant(),
|
||||
const QVariant ¶m4 = QVariant(),
|
||||
const QVariant ¶m5 = QVariant(),
|
||||
const QVariant ¶m6 = QVariant(),
|
||||
const QVariant ¶m7 = QVariant(),
|
||||
const QVariant ¶m8 = QVariant(),
|
||||
const QVariant ¶m9 = QVariant(),
|
||||
const QVariant ¶m10 = QVariant()) const;
|
||||
|
||||
Q_INVOKABLE QString xi18nc(const QString &context,
|
||||
const QString &message,
|
||||
const QVariant ¶m1 = QVariant(),
|
||||
const QVariant ¶m2 = QVariant(),
|
||||
const QVariant ¶m3 = QVariant(),
|
||||
const QVariant ¶m4 = QVariant(),
|
||||
const QVariant ¶m5 = QVariant(),
|
||||
const QVariant ¶m6 = QVariant(),
|
||||
const QVariant ¶m7 = QVariant(),
|
||||
const QVariant ¶m8 = QVariant(),
|
||||
const QVariant ¶m9 = QVariant(),
|
||||
const QVariant ¶m10 = QVariant()) const;
|
||||
|
||||
Q_INVOKABLE QString xi18np(const QString &singular,
|
||||
const QString &plural,
|
||||
const QVariant ¶m1 = QVariant(),
|
||||
const QVariant ¶m2 = QVariant(),
|
||||
const QVariant ¶m3 = QVariant(),
|
||||
const QVariant ¶m4 = QVariant(),
|
||||
const QVariant ¶m5 = QVariant(),
|
||||
const QVariant ¶m6 = QVariant(),
|
||||
const QVariant ¶m7 = QVariant(),
|
||||
const QVariant ¶m8 = QVariant(),
|
||||
const QVariant ¶m9 = QVariant(),
|
||||
const QVariant ¶m10 = QVariant()) const;
|
||||
|
||||
Q_INVOKABLE QString xi18ncp(const QString &context,
|
||||
const QString &singular,
|
||||
const QString &plural,
|
||||
const QVariant ¶m1 = QVariant(),
|
||||
const QVariant ¶m2 = QVariant(),
|
||||
const QVariant ¶m3 = QVariant(),
|
||||
const QVariant ¶m4 = QVariant(),
|
||||
const QVariant ¶m5 = QVariant(),
|
||||
const QVariant ¶m6 = QVariant(),
|
||||
const QVariant ¶m7 = QVariant(),
|
||||
const QVariant ¶m8 = QVariant(),
|
||||
const QVariant ¶m9 = QVariant(),
|
||||
const QVariant ¶m10 = QVariant()) const;
|
||||
|
||||
Q_INVOKABLE QString xi18nd(const QString &domain,
|
||||
const QString &message,
|
||||
const QVariant ¶m1 = QVariant(),
|
||||
const QVariant ¶m2 = QVariant(),
|
||||
const QVariant ¶m3 = QVariant(),
|
||||
const QVariant ¶m4 = QVariant(),
|
||||
const QVariant ¶m5 = QVariant(),
|
||||
const QVariant ¶m6 = QVariant(),
|
||||
const QVariant ¶m7 = QVariant(),
|
||||
const QVariant ¶m8 = QVariant(),
|
||||
const QVariant ¶m9 = QVariant(),
|
||||
const QVariant ¶m10 = QVariant()) const;
|
||||
|
||||
Q_INVOKABLE QString xi18ndc(const QString &domain,
|
||||
const QString &context,
|
||||
const QString &message,
|
||||
const QVariant ¶m1 = QVariant(),
|
||||
const QVariant ¶m2 = QVariant(),
|
||||
const QVariant ¶m3 = QVariant(),
|
||||
const QVariant ¶m4 = QVariant(),
|
||||
const QVariant ¶m5 = QVariant(),
|
||||
const QVariant ¶m6 = QVariant(),
|
||||
const QVariant ¶m7 = QVariant(),
|
||||
const QVariant ¶m8 = QVariant(),
|
||||
const QVariant ¶m9 = QVariant(),
|
||||
const QVariant ¶m10 = QVariant()) const;
|
||||
|
||||
Q_INVOKABLE QString xi18ndp(const QString &domain,
|
||||
const QString &singular,
|
||||
const QString &plural,
|
||||
const QVariant ¶m1 = QVariant(),
|
||||
const QVariant ¶m2 = QVariant(),
|
||||
const QVariant ¶m3 = QVariant(),
|
||||
const QVariant ¶m4 = QVariant(),
|
||||
const QVariant ¶m5 = QVariant(),
|
||||
const QVariant ¶m6 = QVariant(),
|
||||
const QVariant ¶m7 = QVariant(),
|
||||
const QVariant ¶m8 = QVariant(),
|
||||
const QVariant ¶m9 = QVariant(),
|
||||
const QVariant ¶m10 = QVariant()) const;
|
||||
|
||||
Q_INVOKABLE QString xi18ndcp(const QString &domain,
|
||||
const QString &context,
|
||||
const QString &singular,
|
||||
const QString &plural,
|
||||
const QVariant ¶m1 = QVariant(),
|
||||
const QVariant ¶m2 = QVariant(),
|
||||
const QVariant ¶m3 = QVariant(),
|
||||
const QVariant ¶m4 = QVariant(),
|
||||
const QVariant ¶m5 = QVariant(),
|
||||
const QVariant ¶m6 = QVariant(),
|
||||
const QVariant ¶m7 = QVariant(),
|
||||
const QVariant ¶m8 = QVariant(),
|
||||
const QVariant ¶m9 = QVariant(),
|
||||
const QVariant ¶m10 = QVariant()) const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void translationDomainChanged(const QString &translationDomain);
|
||||
|
||||
private:
|
||||
bool eventFilter(QObject *watched, QEvent *event) override;
|
||||
std::unique_ptr<KLocalizedQmlContextPrivate> const d;
|
||||
};
|
||||
|
||||
namespace KLocalization
|
||||
{
|
||||
///@cond internal
|
||||
namespace Internal
|
||||
{
|
||||
[[nodiscard]] KI18NQML_EXPORT KLocalizedQmlContext *createLocalizedContext(QQmlEngine *engine);
|
||||
}
|
||||
///@endcond
|
||||
|
||||
/** Creates a KLocalizedQmlContext engine and sets it up in the
|
||||
* root context of @p engine.
|
||||
*
|
||||
* If @p TRANSLATION_DOMAIN is defined, that is also set on
|
||||
* the created context.
|
||||
*
|
||||
* @since 6.8
|
||||
*/
|
||||
inline KLocalizedQmlContext *setupLocalizedContext(QQmlEngine *engine)
|
||||
{
|
||||
auto ctx = Internal::createLocalizedContext(engine);
|
||||
#ifdef TRANSLATION_DOMAIN
|
||||
ctx->setTranslationDomain(QStringLiteral(TRANSLATION_DOMAIN));
|
||||
#endif
|
||||
return ctx;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,140 @@
|
||||
if (NOT BUILD_SHARED_LIBS AND BUILD_WITH_QML)
|
||||
set(HAVE_STATIC_KTRANSCRIPT ON)
|
||||
else()
|
||||
set(HAVE_STATIC_KTRANSCRIPT OFF)
|
||||
endif()
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/config.h.in" "${CMAKE_CURRENT_BINARY_DIR}/config.h")
|
||||
|
||||
add_library(KF6I18n)
|
||||
add_library(KF6::I18n ALIAS KF6I18n)
|
||||
|
||||
set_target_properties(KF6I18n PROPERTIES
|
||||
VERSION ${KI18N_VERSION}
|
||||
SOVERSION ${KI18N_SOVERSION}
|
||||
EXPORT_NAME I18n
|
||||
)
|
||||
|
||||
target_sources(KF6I18n PRIVATE
|
||||
klocalizedstring.cpp
|
||||
klocalizedtranslator.cpp
|
||||
kcatalog.cpp
|
||||
kuitsetup.cpp
|
||||
common_helpers.cpp
|
||||
klocalizedcontext.cpp
|
||||
main.cpp
|
||||
klocalization.cpp
|
||||
)
|
||||
|
||||
ecm_qt_declare_logging_category(KF6I18n
|
||||
HEADER ki18n_logging.h
|
||||
IDENTIFIER KI18N
|
||||
CATEGORY_NAME kf.i18n
|
||||
OLD_CATEGORY_NAMES kf5.ki18n
|
||||
DESCRIPTION "KI18n"
|
||||
EXPORT KI18N
|
||||
)
|
||||
|
||||
ecm_qt_declare_logging_category(KF6I18n
|
||||
HEADER ki18n_logging_kuit.h
|
||||
IDENTIFIER KI18N_KUIT
|
||||
CATEGORY_NAME kf.i18n.kuit
|
||||
OLD_CATEGORY_NAMES kf5.ki18n.kuit
|
||||
DESCRIPTION "KI18n KUIT"
|
||||
EXPORT KI18N
|
||||
)
|
||||
|
||||
ecm_generate_export_header(KF6I18n
|
||||
BASE_NAME KI18n
|
||||
GROUP_BASE_NAME KF
|
||||
VERSION ${KF_VERSION}
|
||||
USE_VERSION_HEADER
|
||||
DEPRECATED_BASE_VERSION 0
|
||||
DEPRECATION_VERSIONS 6.8
|
||||
EXCLUDE_DEPRECATED_BEFORE_AND_AT ${EXCLUDE_DEPRECATED_BEFORE_AND_AT}
|
||||
)
|
||||
|
||||
target_include_directories(KF6I18n
|
||||
INTERFACE "$<INSTALL_INTERFACE:${KDE_INSTALL_INCLUDEDIR_KF}/KI18n>"
|
||||
PUBLIC "$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}>" # for version header
|
||||
PRIVATE ${LibIntl_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
target_link_libraries(KF6I18n PUBLIC Qt6::Core)
|
||||
# This is only required for platforms which don't use glibc (with glibc LibIntl_LIBRARIES will be empty)
|
||||
target_link_libraries(KF6I18n PRIVATE ${LibIntl_LIBRARIES})
|
||||
if (ANDROID)
|
||||
target_link_libraries(KF6I18n PRIVATE android)
|
||||
endif()
|
||||
target_compile_options(KF6I18n PRIVATE -DTRANSLATION_DOMAIN=\"ki18n6\")
|
||||
|
||||
install(TARGETS KF6I18n EXPORT KF6I18nTargets ${KF_INSTALL_TARGETS_DEFAULT_ARGS})
|
||||
|
||||
ecm_generate_headers(KI18n_HEADERS
|
||||
HEADER_NAMES
|
||||
KLazyLocalizedString
|
||||
KLocalizedContext
|
||||
KLocalizedString
|
||||
KLocalizedTranslator
|
||||
KLocalization
|
||||
KuitSetup
|
||||
REQUIRED_HEADERS KI18n_HEADERS
|
||||
)
|
||||
|
||||
install(FILES
|
||||
${KI18n_HEADERS}
|
||||
${CMAKE_CURRENT_BINARY_DIR}/ki18n_export.h
|
||||
DESTINATION "${KDE_INSTALL_INCLUDEDIR_KF}/KI18n" COMPONENT Devel
|
||||
)
|
||||
|
||||
|
||||
### ktranscript plugin
|
||||
if (BUILD_WITH_QML)
|
||||
|
||||
if (BUILD_SHARED_LIBS)
|
||||
add_library(ktranscript MODULE)
|
||||
else()
|
||||
add_library(ktranscript)
|
||||
endif()
|
||||
|
||||
target_sources(ktranscript PRIVATE
|
||||
ktranscript.cpp
|
||||
common_helpers.cpp
|
||||
)
|
||||
generate_export_header(ktranscript BASE_NAME KTranscript)
|
||||
target_link_libraries(ktranscript PRIVATE Qt6::Qml Qt6::Core)
|
||||
|
||||
if (BUILD_SHARED_LIBS)
|
||||
install(TARGETS ktranscript DESTINATION ${KDE_INSTALL_PLUGINDIR}/kf6)
|
||||
else()
|
||||
target_link_libraries(KF6I18n PRIVATE ktranscript)
|
||||
install(TARGETS ktranscript EXPORT KF6I18nTargets DESTINATION ${KF_INSTALL_TARGETS_DEFAULT_ARGS})
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
if (BUILD_QCH)
|
||||
ecm_add_qch(
|
||||
KF6I18n_QCH
|
||||
NAME KI18n
|
||||
BASE_NAME KF6I18n
|
||||
VERSION ${KF_VERSION}
|
||||
ORG_DOMAIN org.kde
|
||||
SOURCES # using only public headers, to cover only public API
|
||||
${KI18n_HEADERS}
|
||||
"${CMAKE_SOURCE_DIR}/docs/programmers-guide.md"
|
||||
"${CMAKE_SOURCE_DIR}/docs/translators-guide.md"
|
||||
MD_MAINPAGE "${CMAKE_SOURCE_DIR}/README.md"
|
||||
LINK_QCHS
|
||||
Qt6Core_QCH
|
||||
INCLUDE_DIRS
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
BLANK_MACROS
|
||||
KI18N_EXPORT
|
||||
KI18N_DEPRECATED_EXPORT
|
||||
KI18N_DEPRECATED
|
||||
"KI18N_DEPRECATED_VERSION(x, y, t)"
|
||||
TAGFILE_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR}
|
||||
QCH_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR}
|
||||
COMPONENT Devel
|
||||
)
|
||||
endif()
|
||||
@@ -0,0 +1,2 @@
|
||||
#! /usr/bin/env bash
|
||||
$XGETTEXT *.cpp *.h -o $podir/ki18n6.pot
|
||||
@@ -0,0 +1,96 @@
|
||||
/* This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2008 Chusslove Illich <caslav.ilic@gmx.net>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include <common_helpers_p.h>
|
||||
|
||||
// If pos points to alphanumeric X in "...(X)...", which is preceded or
|
||||
// followed only by non-alphanumerics, then "(X)" gets removed.
|
||||
static QString removeReducedCJKAccMark(const QString &label, int pos)
|
||||
{
|
||||
if (pos > 0 && pos + 1 < label.length() //
|
||||
&& label[pos - 1] == QLatin1Char('(') //
|
||||
&& label[pos + 1] == QLatin1Char(')') //
|
||||
&& label[pos].isLetterOrNumber()) {
|
||||
// Check if at start or end, ignoring non-alphanumerics.
|
||||
int len = label.length();
|
||||
int p1 = pos - 2;
|
||||
while (p1 >= 0 && !label[p1].isLetterOrNumber()) {
|
||||
--p1;
|
||||
}
|
||||
++p1;
|
||||
int p2 = pos + 2;
|
||||
while (p2 < len && !label[p2].isLetterOrNumber()) {
|
||||
++p2;
|
||||
}
|
||||
--p2;
|
||||
|
||||
const QStringView labelView(label);
|
||||
if (p1 == 0) {
|
||||
return labelView.left(pos - 1) + labelView.mid(p2 + 1);
|
||||
} else if (p2 + 1 == len) {
|
||||
return labelView.left(p1) + labelView.mid(pos + 2);
|
||||
}
|
||||
}
|
||||
return label;
|
||||
}
|
||||
|
||||
QString removeAcceleratorMarker(const QString &label_)
|
||||
{
|
||||
QString label = label_;
|
||||
|
||||
int p = 0;
|
||||
bool accmarkRemoved = false;
|
||||
while (true) {
|
||||
p = label.indexOf(QLatin1Char('&'), p);
|
||||
if (p < 0 || p + 1 == label.length()) {
|
||||
break;
|
||||
}
|
||||
|
||||
const QStringView labelView(label);
|
||||
const QChar marker = label.at(p + 1);
|
||||
if (marker.isLetterOrNumber()) {
|
||||
// Valid accelerator.
|
||||
label = labelView.left(p) + labelView.mid(p + 1);
|
||||
|
||||
// May have been an accelerator in CJK-style "(&X)"
|
||||
// at the start or end of text.
|
||||
label = removeReducedCJKAccMark(label, p);
|
||||
|
||||
accmarkRemoved = true;
|
||||
} else if (marker == QLatin1Char('&')) {
|
||||
// Escaped accelerator marker.
|
||||
label = labelView.left(p) + labelView.mid(p + 1);
|
||||
}
|
||||
|
||||
++p;
|
||||
}
|
||||
|
||||
// If no marker was removed, and there are CJK characters in the label,
|
||||
// also try to remove reduced CJK marker -- something may have removed
|
||||
// ampersand beforehand.
|
||||
if (!accmarkRemoved) {
|
||||
bool hasCJK = false;
|
||||
for (const QChar c : std::as_const(label)) {
|
||||
if (c.unicode() >= 0x2e00) { // rough, but should be sufficient
|
||||
hasCJK = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasCJK) {
|
||||
p = 0;
|
||||
while (true) {
|
||||
p = label.indexOf(QLatin1Char('('), p);
|
||||
if (p < 0) {
|
||||
break;
|
||||
}
|
||||
label = removeReducedCJKAccMark(label, p + 1);
|
||||
++p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return label;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/* This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2008 Chusslove Illich <caslav.ilic@gmx.net>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef COMMON_HELPERS_P_H
|
||||
#define COMMON_HELPERS_P_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
// Standalone (pure Qt) functionality needed internally in more than
|
||||
// one source file on localization.
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* Removes accelerator marker from a UI text label.
|
||||
*
|
||||
* Accelerator marker is not always a plain ampersand (&),
|
||||
* so it is not enough to just remove it by @c QString::remove().
|
||||
* The label may contain escaped markers ("&&") which must be resolved
|
||||
* and skipped, as well as CJK-style markers ("Foo (&F)") where
|
||||
* the whole parenthesis construct should be removed.
|
||||
* Therefore always use this function to remove accelerator marker
|
||||
* from UI labels.
|
||||
*
|
||||
* @param label UI label which may contain an accelerator marker
|
||||
* @return label without the accelerator marker
|
||||
*/
|
||||
QString removeAcceleratorMarker(const QString &label);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,16 @@
|
||||
/* This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2016 A. Wilcox <awilfox@adelielinux.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef KI18N_CONFIG_H
|
||||
#define KI18N_CONFIG_H
|
||||
|
||||
#cmakedefine01 HAVE_NL_MSG_CAT_CNTR
|
||||
|
||||
#define INSTALLED_LOCALE_PREFIX "@IsoCodes_PREFIX@"
|
||||
|
||||
#cmakedefine01 HAVE_STATIC_KTRANSCRIPT
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,187 @@
|
||||
/* Convenience header for conditional use of GNU <libintl.h>.
|
||||
SPDX-FileCopyrightText: 1995-1998, 2000-2002, 2004-2006 Free Software Foundation, Inc.
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
// clang-format off
|
||||
#ifndef _LIBGETTEXT_H
|
||||
#define _LIBGETTEXT_H 1
|
||||
|
||||
/* Get declarations of GNU message catalog functions. */
|
||||
# include <libintl.h>
|
||||
// libintl.h redefines inline which causes MSVC to abort compilation with the message
|
||||
// fatal error C1189: #error : The C++ Standard Library forbids macroizing keywords
|
||||
#undef inline
|
||||
|
||||
/* You can set the DEFAULT_TEXT_DOMAIN macro to specify the domain used by
|
||||
the gettext() and ngettext() macros. This is an alternative to calling
|
||||
textdomain(), and is useful for libraries. */
|
||||
# ifdef DEFAULT_TEXT_DOMAIN
|
||||
# undef gettext
|
||||
# define gettext(Msgid) \
|
||||
dgettext (DEFAULT_TEXT_DOMAIN, Msgid)
|
||||
# undef ngettext
|
||||
# define ngettext(Msgid1, Msgid2, N) \
|
||||
dngettext (DEFAULT_TEXT_DOMAIN, Msgid1, Msgid2, N)
|
||||
# endif
|
||||
|
||||
/* The separator between msgctxt and msgid in a .mo file. */
|
||||
#define GETTEXT_CONTEXT_GLUE "\004"
|
||||
|
||||
/* Pseudo function calls, taking a MSGCTXT and a MSGID instead of just a
|
||||
MSGID. MSGCTXT and MSGID must be string literals. MSGCTXT should be
|
||||
short and rarely need to change.
|
||||
The letter 'p' stands for 'particular' or 'special'. */
|
||||
#ifdef DEFAULT_TEXT_DOMAIN
|
||||
# define pgettext(Msgctxt, Msgid) \
|
||||
pgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid)
|
||||
#else
|
||||
# define pgettext(Msgctxt, Msgid) \
|
||||
pgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid)
|
||||
#endif
|
||||
#define dpgettext(Domainname, Msgctxt, Msgid) \
|
||||
pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid)
|
||||
|
||||
#ifdef __GNUC__
|
||||
__inline
|
||||
#else
|
||||
#ifdef __cplusplus
|
||||
inline
|
||||
#endif
|
||||
#endif
|
||||
static const char *
|
||||
pgettext_aux(const char *domain,
|
||||
const char *msg_ctxt_id, const char *msgid)
|
||||
{
|
||||
const char *translation = dgettext(domain, msg_ctxt_id);
|
||||
if (translation == msg_ctxt_id) {
|
||||
return msgid;
|
||||
} else {
|
||||
return translation;
|
||||
}
|
||||
}
|
||||
|
||||
/* The same thing extended for non-constant arguments. Here MSGCTXT and MSGID
|
||||
can be arbitrary expressions. But for string literals these macros are
|
||||
less efficient than those above. */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifndef __STRICT_ANSI__
|
||||
#define __STRICT_ANSI__
|
||||
#define __STRICT_ANSI_FORCED__
|
||||
#endif
|
||||
|
||||
#define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS \
|
||||
(__STRICT_ANSI__ - 0 == 0) && (__GNUC__ >= 3 || __GNUG__ >= 2 /* || __STDC_VERSION__ >= 199901L */ )
|
||||
|
||||
#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#define pgettext_expr(Msgctxt, Msgid) \
|
||||
dpgettext_expr (NULL, Msgctxt, Msgid)
|
||||
#define dpgettext_expr(Domainname, Msgctxt, Msgid) \
|
||||
dpgettext_expr (Domainname, Msgctxt, Msgid)
|
||||
|
||||
#ifdef __GNUC__
|
||||
__inline
|
||||
#else
|
||||
#ifdef __cplusplus
|
||||
inline
|
||||
#endif
|
||||
#endif
|
||||
static const char *
|
||||
dpgettext_expr(const char *domain,
|
||||
const char *msgctxt, const char *msgid)
|
||||
{
|
||||
size_t msgctxt_len = strlen(msgctxt) + 1;
|
||||
size_t msgid_len = strlen(msgid) + 1;
|
||||
const char *translation;
|
||||
int translation_found;
|
||||
#if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
|
||||
char msg_ctxt_id[msgctxt_len + msgid_len];
|
||||
#else
|
||||
char buf[1024];
|
||||
char *msg_ctxt_id =
|
||||
(msgctxt_len + msgid_len <= sizeof(buf)
|
||||
? buf
|
||||
: (char *) malloc(msgctxt_len + msgid_len));
|
||||
if (msg_ctxt_id != nullptr)
|
||||
#endif
|
||||
{
|
||||
memcpy(msg_ctxt_id, msgctxt, msgctxt_len - 1);
|
||||
msg_ctxt_id[msgctxt_len - 1] = '\004';
|
||||
memcpy(msg_ctxt_id + msgctxt_len, msgid, msgid_len);
|
||||
translation = dgettext(domain, msg_ctxt_id);
|
||||
/* Test must occur before msg_ctxt_id freed */
|
||||
translation_found = translation != msg_ctxt_id;
|
||||
#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
|
||||
if (msg_ctxt_id != buf) {
|
||||
free(msg_ctxt_id);
|
||||
}
|
||||
#endif
|
||||
if (translation_found) {
|
||||
return translation;
|
||||
}
|
||||
}
|
||||
return msgid;
|
||||
}
|
||||
|
||||
#define npgettext_expr(Msgctxt, Msgid, MsgidPlural, N) \
|
||||
dnpgettext_expr (NULL, Msgctxt, Msgid, MsgidPlural, N)
|
||||
#define dnpgettext_expr(Domainname, Msgctxt, Msgid, MsgidPlural, N) \
|
||||
dnpgettext_expr (Domainname, Msgctxt, Msgid, MsgidPlural, N)
|
||||
|
||||
#ifdef __GNUC__
|
||||
__inline
|
||||
#else
|
||||
#ifdef __cplusplus
|
||||
inline
|
||||
#endif
|
||||
#endif
|
||||
static const char *
|
||||
dnpgettext_expr(const char *domain,
|
||||
const char *msgctxt, const char *msgid,
|
||||
const char *msgid_plural, unsigned long int n)
|
||||
{
|
||||
size_t msgctxt_len = strlen(msgctxt) + 1;
|
||||
size_t msgid_len = strlen(msgid) + 1;
|
||||
const char *translation;
|
||||
int translation_found;
|
||||
#if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
|
||||
char msg_ctxt_id[msgctxt_len + msgid_len];
|
||||
#else
|
||||
char buf[1024];
|
||||
char *msg_ctxt_id =
|
||||
(msgctxt_len + msgid_len <= sizeof(buf)
|
||||
? buf
|
||||
: (char *) malloc(msgctxt_len + msgid_len));
|
||||
if (msg_ctxt_id != nullptr)
|
||||
#endif
|
||||
{
|
||||
memcpy(msg_ctxt_id, msgctxt, msgctxt_len - 1);
|
||||
msg_ctxt_id[msgctxt_len - 1] = '\004';
|
||||
memcpy(msg_ctxt_id + msgctxt_len, msgid, msgid_len);
|
||||
translation = dngettext(domain, msg_ctxt_id, msgid_plural, n);
|
||||
/* Test must occur before msg_ctxt_id freed */
|
||||
translation_found = !(translation == msg_ctxt_id || translation == msgid_plural);
|
||||
#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
|
||||
if (msg_ctxt_id != buf) {
|
||||
free(msg_ctxt_id);
|
||||
}
|
||||
#endif
|
||||
if (translation_found) {
|
||||
return translation;
|
||||
}
|
||||
}
|
||||
return (n == 1 ? msgid : msgid_plural);
|
||||
}
|
||||
|
||||
#ifdef __STRICT_ANSI_FORCED__
|
||||
#undef __STRICT_ANSI__
|
||||
#undef __STRICT_ANSI_FORCED__
|
||||
#endif
|
||||
|
||||
#endif /* _LIBGETTEXT_H */
|
||||
// clang-format on
|
||||
@@ -0,0 +1,414 @@
|
||||
/* This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2001 Hans Petter Bieker <bieker@kde.org>
|
||||
SPDX-FileCopyrightText: 2012, 2013 Chusslove Illich <caslav.ilic@gmx.net>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <kcatalog_p.h>
|
||||
|
||||
#include "ki18n_logging.h"
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QCoreApplication>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QMutexLocker>
|
||||
#include <QSet>
|
||||
#include <QStandardPaths>
|
||||
#include <QStringList>
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
#include <QCoreApplication>
|
||||
#include <QJniEnvironment>
|
||||
#include <QJniObject>
|
||||
|
||||
#include <android/asset_manager.h>
|
||||
#include <android/asset_manager_jni.h>
|
||||
|
||||
#if __ANDROID_API__ < 23
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <locale.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "gettext.h" // Must be included after <stdlib.h>
|
||||
|
||||
// not defined on win32 :(
|
||||
#ifdef _WIN32
|
||||
#ifndef LC_MESSAGES
|
||||
#define LC_MESSAGES 42
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if HAVE_NL_MSG_CAT_CNTR
|
||||
extern "C" int Q_DECL_IMPORT _nl_msg_cat_cntr;
|
||||
#endif
|
||||
|
||||
static char *s_langenv = nullptr;
|
||||
static const int s_langenvMaxlen = 64;
|
||||
// = "LANGUAGE=" + 54 chars for language code + terminating null \0 character
|
||||
|
||||
static void copyToLangArr(const QByteArray &lang)
|
||||
{
|
||||
const int bytes = std::snprintf(s_langenv, s_langenvMaxlen, "LANGUAGE=%s", lang.constData());
|
||||
if (bytes < 0) {
|
||||
qCWarning(KI18N) << "There was an error while writing LANGUAGE environment variable:" << std::strerror(errno);
|
||||
} else if (bytes > (s_langenvMaxlen - 1)) { // -1 for the \0 character
|
||||
qCWarning(KI18N) << "The value of the LANGUAGE environment variable:" << lang << "( size:" << lang.size() << "),\n"
|
||||
<< "was longer than (and consequently truncated to) the max. length of:" << (s_langenvMaxlen - strlen("LANGUAGE=") - 1);
|
||||
}
|
||||
}
|
||||
|
||||
class KCatalogStaticData
|
||||
{
|
||||
public:
|
||||
KCatalogStaticData()
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
QJniEnvironment env;
|
||||
QJniObject context = QNativeInterface::QAndroidApplication::context();
|
||||
m_assets = context.callObjectMethod("getAssets", "()Landroid/content/res/AssetManager;");
|
||||
m_assetMgr = AAssetManager_fromJava(env.jniEnv(), m_assets.object());
|
||||
|
||||
#if __ANDROID_API__ < 23
|
||||
fmemopenFunc = reinterpret_cast<decltype(fmemopenFunc)>(dlsym(RTLD_DEFAULT, "fmemopen"));
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
QHash<QByteArray /*domain*/, QString /*directory*/> customCatalogDirs;
|
||||
QMutex mutex;
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
QJniObject m_assets;
|
||||
AAssetManager *m_assetMgr = nullptr;
|
||||
#if __ANDROID_API__ < 23
|
||||
FILE *(*fmemopenFunc)(void *, size_t, const char *);
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
Q_GLOBAL_STATIC(KCatalogStaticData, catalogStaticData)
|
||||
|
||||
class KCatalogPrivate
|
||||
{
|
||||
public:
|
||||
KCatalogPrivate();
|
||||
|
||||
QByteArray domain;
|
||||
QByteArray language;
|
||||
QByteArray localeDir;
|
||||
|
||||
QByteArray systemLanguage;
|
||||
bool bindDone;
|
||||
|
||||
static QByteArray currentLanguage;
|
||||
|
||||
void setupGettextEnv();
|
||||
void resetSystemLanguage();
|
||||
};
|
||||
|
||||
KCatalogPrivate::KCatalogPrivate()
|
||||
: bindDone(false)
|
||||
{
|
||||
}
|
||||
|
||||
QByteArray KCatalogPrivate::currentLanguage;
|
||||
|
||||
KCatalog::KCatalog(const QByteArray &domain, const QString &language_)
|
||||
: d(new KCatalogPrivate)
|
||||
{
|
||||
d->domain = domain;
|
||||
d->language = QFile::encodeName(language_);
|
||||
d->localeDir = QFile::encodeName(catalogLocaleDir(domain, language_));
|
||||
|
||||
if (!d->localeDir.isEmpty()) {
|
||||
// Always get translations in UTF-8, regardless of user's environment.
|
||||
bind_textdomain_codeset(d->domain, "UTF-8");
|
||||
|
||||
// Invalidate current language, to trigger binding at next translate call.
|
||||
KCatalogPrivate::currentLanguage.clear();
|
||||
|
||||
if (!s_langenv) {
|
||||
// Call putenv only here, to initialize LANGUAGE variable.
|
||||
// Later only change s_langenv to what is currently needed.
|
||||
// This doesn't work on Windows though, so there we need putenv calls on every change
|
||||
s_langenv = new char[s_langenvMaxlen];
|
||||
copyToLangArr(qgetenv("LANGUAGE"));
|
||||
putenv(s_langenv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
KCatalog::~KCatalog() = default;
|
||||
|
||||
#if defined(Q_OS_ANDROID) && __ANDROID_API__ < 23
|
||||
static QString androidUnpackCatalog(const QString &relpath)
|
||||
{
|
||||
// the catalog files are no longer extracted to the local file system
|
||||
// by androiddeployqt starting with Qt 5.14, libintl however needs
|
||||
// local files rather than qrc: or asset: URLs, so we unpack the .mo
|
||||
// files on demand to the local cache folder
|
||||
|
||||
const QString cachePath = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QLatin1String("/org.kde.ki18n/") + relpath;
|
||||
QFileInfo cacheFile(cachePath);
|
||||
if (cacheFile.exists()) {
|
||||
return cachePath;
|
||||
}
|
||||
|
||||
const QString assetPath = QLatin1String("assets:/share/locale/") + relpath;
|
||||
if (!QFileInfo::exists(assetPath)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
QDir().mkpath(cacheFile.absolutePath());
|
||||
QFile f(assetPath);
|
||||
if (!f.copy(cachePath)) {
|
||||
qCWarning(KI18N) << "Failed to copy catalog:" << f.errorString() << assetPath << cachePath;
|
||||
return {};
|
||||
}
|
||||
return cachePath;
|
||||
}
|
||||
#endif
|
||||
|
||||
QString KCatalog::catalogLocaleDir(const QByteArray &domain, const QString &language)
|
||||
{
|
||||
QString relpath = QStringLiteral("%1/LC_MESSAGES/%2.mo").arg(language, QFile::decodeName(domain));
|
||||
|
||||
{
|
||||
QMutexLocker lock(&catalogStaticData->mutex);
|
||||
const QString customLocaleDir = catalogStaticData->customCatalogDirs.value(domain);
|
||||
const QString filename = customLocaleDir + QLatin1Char('/') + relpath;
|
||||
if (!customLocaleDir.isEmpty() && QFileInfo::exists(filename)) {
|
||||
#if defined(Q_OS_ANDROID)
|
||||
// The exact file name must be returned on Android because libintl-lite loads a catalog by filename with bindtextdomain()
|
||||
return filename;
|
||||
#else
|
||||
return customLocaleDir;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(Q_OS_ANDROID)
|
||||
#if __ANDROID_API__ < 23
|
||||
// fall back to copying the catalog to the file system on old systems
|
||||
// without fmemopen()
|
||||
if (!catalogStaticData->fmemopenFunc) {
|
||||
return androidUnpackCatalog(relpath);
|
||||
}
|
||||
#endif
|
||||
const QString assetPath = QLatin1String("assets:/share/locale/") + relpath;
|
||||
if (!QFileInfo::exists(assetPath)) {
|
||||
return {};
|
||||
}
|
||||
return assetPath;
|
||||
|
||||
#else
|
||||
QString file = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("locale/") + relpath);
|
||||
#ifdef Q_OS_WIN
|
||||
// QStandardPaths fails on Windows for executables that aren't properly deployed yet, such as unit tests
|
||||
if (file.isEmpty()) {
|
||||
const QString p = QLatin1String(INSTALLED_LOCALE_PREFIX) + QLatin1String("/bin/data/locale/") + relpath;
|
||||
if (QFile::exists(p)) {
|
||||
file = p;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
QString localeDir;
|
||||
if (!file.isEmpty()) {
|
||||
// Path of the locale/ directory must be returned.
|
||||
localeDir = QFileInfo(file.left(file.size() - relpath.size())).absolutePath();
|
||||
}
|
||||
return localeDir;
|
||||
#endif
|
||||
}
|
||||
|
||||
QSet<QString> KCatalog::availableCatalogLanguages(const QByteArray &domain_)
|
||||
{
|
||||
QString domain = QFile::decodeName(domain_);
|
||||
QStringList localeDirPaths = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("locale"), QStandardPaths::LocateDirectory);
|
||||
#ifdef Q_OS_WIN
|
||||
// QStandardPaths fails on Windows for executables that aren't properly deployed yet, such as unit tests
|
||||
localeDirPaths += QLatin1String(INSTALLED_LOCALE_PREFIX) + QLatin1String("/bin/data/locale/");
|
||||
#endif
|
||||
|
||||
{
|
||||
QMutexLocker lock(&catalogStaticData->mutex);
|
||||
auto it = catalogStaticData->customCatalogDirs.constFind(domain_);
|
||||
if (it != catalogStaticData->customCatalogDirs.constEnd()) {
|
||||
localeDirPaths.prepend(*it);
|
||||
}
|
||||
}
|
||||
|
||||
QSet<QString> availableLanguages;
|
||||
for (const QString &localDirPath : std::as_const(localeDirPaths)) {
|
||||
QDir localeDir(localDirPath);
|
||||
const QStringList languages = localeDir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot);
|
||||
for (const QString &language : languages) {
|
||||
QString relPath = QStringLiteral("%1/LC_MESSAGES/%2.mo").arg(language, domain);
|
||||
if (localeDir.exists(relPath)) {
|
||||
availableLanguages.insert(language);
|
||||
}
|
||||
}
|
||||
}
|
||||
return availableLanguages;
|
||||
}
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
static void androidAssetBindtextdomain(const QByteArray &domain, const QByteArray &localeDir)
|
||||
{
|
||||
AAsset *asset = AAssetManager_open(catalogStaticData->m_assetMgr, localeDir.mid(8).constData(), AASSET_MODE_UNKNOWN);
|
||||
if (!asset) {
|
||||
qWarning() << "unable to load asset" << localeDir;
|
||||
return;
|
||||
}
|
||||
|
||||
off64_t size = AAsset_getLength64(asset);
|
||||
const void *buffer = AAsset_getBuffer(asset);
|
||||
#if __ANDROID_API__ >= 23
|
||||
FILE *moFile = fmemopen(const_cast<void *>(buffer), size, "r");
|
||||
#else
|
||||
FILE *moFile = catalogStaticData->fmemopenFunc(const_cast<void *>(buffer), size, "r");
|
||||
#endif
|
||||
loadMessageCatalogFile(domain, moFile);
|
||||
fclose(moFile);
|
||||
AAsset_close(asset);
|
||||
}
|
||||
#endif
|
||||
|
||||
void KCatalogPrivate::setupGettextEnv()
|
||||
{
|
||||
// Point Gettext to current language, recording system value for recovery.
|
||||
systemLanguage = qgetenv("LANGUAGE");
|
||||
if (systemLanguage != language) {
|
||||
// putenv has been called in the constructor,
|
||||
// it is enough to change the string set there.
|
||||
copyToLangArr(language);
|
||||
#ifdef Q_OS_WINDOWS
|
||||
putenv(s_langenv);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Rebind text domain if language actually changed from the last time,
|
||||
// as locale directories may differ for different languages of same catalog.
|
||||
if (language != currentLanguage || !bindDone) {
|
||||
Q_ASSERT_X(QCoreApplication::instance(), "KCatalogPrivate::setupGettextEnv", "You need to instantiate a Q*Application before using KCatalog");
|
||||
if (!QCoreApplication::instance()) {
|
||||
qCWarning(KI18N) << "KCatalog being used without a Q*Application instance. Some translations won't work";
|
||||
}
|
||||
|
||||
currentLanguage = language;
|
||||
bindDone = true;
|
||||
|
||||
// qDebug() << "bindtextdomain" << domain << localeDir;
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (localeDir.startsWith("assets:/")) {
|
||||
androidAssetBindtextdomain(domain, localeDir);
|
||||
} else {
|
||||
bindtextdomain(domain, localeDir);
|
||||
}
|
||||
#else
|
||||
bindtextdomain(domain, localeDir);
|
||||
#endif
|
||||
|
||||
#if HAVE_NL_MSG_CAT_CNTR
|
||||
// Magic to make sure GNU Gettext doesn't use stale cached translation
|
||||
// from previous language.
|
||||
++_nl_msg_cat_cntr;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void KCatalogPrivate::resetSystemLanguage()
|
||||
{
|
||||
if (language != systemLanguage) {
|
||||
copyToLangArr(systemLanguage);
|
||||
#ifdef Q_OS_WINDOWS
|
||||
putenv(s_langenv);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
QString KCatalog::translate(const QByteArray &msgid) const
|
||||
{
|
||||
if (!d->localeDir.isEmpty()) {
|
||||
QMutexLocker locker(&catalogStaticData()->mutex);
|
||||
d->setupGettextEnv();
|
||||
const char *msgid_char = msgid.constData();
|
||||
const char *msgstr = dgettext(d->domain.constData(), msgid_char);
|
||||
d->resetSystemLanguage();
|
||||
return msgstr != msgid_char // Yes we want pointer comparison
|
||||
? QString::fromUtf8(msgstr)
|
||||
: QString();
|
||||
} else {
|
||||
return QString();
|
||||
}
|
||||
}
|
||||
|
||||
QString KCatalog::translate(const QByteArray &msgctxt, const QByteArray &msgid) const
|
||||
{
|
||||
if (!d->localeDir.isEmpty()) {
|
||||
QMutexLocker locker(&catalogStaticData()->mutex);
|
||||
d->setupGettextEnv();
|
||||
const char *msgid_char = msgid.constData();
|
||||
const char *msgstr = dpgettext_expr(d->domain.constData(), msgctxt.constData(), msgid_char);
|
||||
d->resetSystemLanguage();
|
||||
return msgstr != msgid_char // Yes we want pointer comparison
|
||||
? QString::fromUtf8(msgstr)
|
||||
: QString();
|
||||
} else {
|
||||
return QString();
|
||||
}
|
||||
}
|
||||
|
||||
QString KCatalog::translate(const QByteArray &msgid, const QByteArray &msgid_plural, qulonglong n) const
|
||||
{
|
||||
if (!d->localeDir.isEmpty()) {
|
||||
QMutexLocker locker(&catalogStaticData()->mutex);
|
||||
d->setupGettextEnv();
|
||||
const char *msgid_char = msgid.constData();
|
||||
const char *msgid_plural_char = msgid_plural.constData();
|
||||
const char *msgstr = dngettext(d->domain.constData(), msgid_char, msgid_plural_char, n);
|
||||
d->resetSystemLanguage();
|
||||
// If original and translation are same, dngettext will return
|
||||
// the original pointer, which is generally fine, except in
|
||||
// the corner cases where e.g. msgstr[1] is same as msgid.
|
||||
// Therefore check for pointer difference only with msgid or
|
||||
// only with msgid_plural, and not with both.
|
||||
return (n == 1 && msgstr != msgid_char) || (n != 1 && msgstr != msgid_plural_char) ? QString::fromUtf8(msgstr) : QString();
|
||||
} else {
|
||||
return QString();
|
||||
}
|
||||
}
|
||||
|
||||
QString KCatalog::translate(const QByteArray &msgctxt, const QByteArray &msgid, const QByteArray &msgid_plural, qulonglong n) const
|
||||
{
|
||||
if (!d->localeDir.isEmpty()) {
|
||||
QMutexLocker locker(&catalogStaticData()->mutex);
|
||||
d->setupGettextEnv();
|
||||
const char *msgid_char = msgid.constData();
|
||||
const char *msgid_plural_char = msgid_plural.constData();
|
||||
const char *msgstr = dnpgettext_expr(d->domain.constData(), msgctxt.constData(), msgid_char, msgid_plural_char, n);
|
||||
d->resetSystemLanguage();
|
||||
return (n == 1 && msgstr != msgid_char) || (n != 1 && msgstr != msgid_plural_char) ? QString::fromUtf8(msgstr) : QString();
|
||||
} else {
|
||||
return QString();
|
||||
}
|
||||
}
|
||||
|
||||
void KCatalog::addDomainLocaleDir(const QByteArray &domain, const QString &path)
|
||||
{
|
||||
QMutexLocker locker(&catalogStaticData()->mutex);
|
||||
catalogStaticData()->customCatalogDirs.insert(domain, path);
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/* This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2001 Hans Petter Bieker <bieker@kde.org>
|
||||
SPDX-FileCopyrightText: 2012, 2013 Chusslove Illich <caslav.ilic@gmx.net>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef KCATALOG_H
|
||||
#define KCATALOG_H
|
||||
|
||||
#include "ki18n_export.h"
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QSet>
|
||||
#include <QString>
|
||||
#include <memory>
|
||||
|
||||
class KCatalogPrivate;
|
||||
|
||||
/**
|
||||
* This class abstracts a Gettext message catalog.
|
||||
* It takes care of needed Gettext bindings.
|
||||
*
|
||||
* @see KLocalizedString
|
||||
* @internal exported only for use in KI18nLocaleData.
|
||||
*/
|
||||
class KI18N_EXPORT KCatalog
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param name translation domain
|
||||
* @param language translation language
|
||||
*/
|
||||
KCatalog(const QByteArray &domain, const QString &language);
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~KCatalog();
|
||||
|
||||
/**
|
||||
* Get translation of the given message text.
|
||||
*
|
||||
* Do not pass empty message text.
|
||||
*
|
||||
* @param msgid message text
|
||||
*
|
||||
* @return translated message if found, <tt>QString()</tt> otherwise
|
||||
*/
|
||||
QString translate(const QByteArray &msgid) const;
|
||||
|
||||
/**
|
||||
* Get translation of the given message text with given context.
|
||||
*
|
||||
* Do not pass empty message text.
|
||||
*
|
||||
* @param msgctxt message context
|
||||
* @param msgid message text
|
||||
*
|
||||
* @return translated message if found, <tt>QString()</tt> otherwise
|
||||
*/
|
||||
QString translate(const QByteArray &msgctxt, const QByteArray &msgid) const;
|
||||
|
||||
/**
|
||||
* Get translation of given message with plural forms.
|
||||
*
|
||||
* Do not pass empty message text.
|
||||
*
|
||||
* @param msgid singular message text
|
||||
* @param msgid_plural plural message text
|
||||
* @param n number for which the plural form is needed
|
||||
*
|
||||
* @return translated message if found, <tt>QString()</tt> otherwise
|
||||
*/
|
||||
QString translate(const QByteArray &msgid, const QByteArray &msgid_plural, qulonglong n) const;
|
||||
|
||||
/**
|
||||
* Get translation of given message with plural forms with given context.
|
||||
*
|
||||
* Do not pass empty message text.
|
||||
*
|
||||
* @param msgctxt message context
|
||||
* @param msgid singular message text
|
||||
* @param msgid_plural plural message text
|
||||
* @param n number for which the plural form is needed
|
||||
*
|
||||
* @return translated message if found, <tt>QString()</tt> otherwise
|
||||
*/
|
||||
QString translate(const QByteArray &msgctxt, const QByteArray &msgid, const QByteArray &msgid_plural, qulonglong n) const;
|
||||
|
||||
/**
|
||||
* Find the locale directory for the given domain in the given language.
|
||||
*
|
||||
* @param domain translation domain
|
||||
* @param language language of the catalog
|
||||
*
|
||||
* @return the locale directory if found, <tt>QByteArray()</tt> otherwise.
|
||||
*/
|
||||
static QString catalogLocaleDir(const QByteArray &domain, const QString &language);
|
||||
|
||||
/**
|
||||
* Find the all languages for which the translation catalog
|
||||
* of given domain exists.
|
||||
*
|
||||
* @param domain translation domain
|
||||
*
|
||||
* @return set of language codes
|
||||
*/
|
||||
static QSet<QString> availableCatalogLanguages(const QByteArray &domain);
|
||||
|
||||
static void addDomainLocaleDir(const QByteArray &domain, const QString &path);
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(KCatalog)
|
||||
|
||||
std::unique_ptr<KCatalogPrivate> const d;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,555 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef KLAZYLOCALIZEDSTRING_H
|
||||
#define KLAZYLOCALIZEDSTRING_H
|
||||
|
||||
#include "klocalizedstring.h"
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
/**
|
||||
* @class KLazyLocalizedString klazylocalizedstring.h <KLazyLocalizedString>
|
||||
*
|
||||
* Lazy-initialized variant of KLocalizedString.
|
||||
*
|
||||
* This is a safer replacement for the I18N_NOOP set of macros and allows
|
||||
* marking strings for extraction without runtime-initializing KLocalizedString instances,
|
||||
* for storing in static data tables.
|
||||
*
|
||||
* Instances of KLazyLocalizedString are not created directly, unless they should be empty.
|
||||
* Instead they have to be obtained via the kli18n* functions (similar to KLocalizedString
|
||||
* and the ki18n* functions).
|
||||
*
|
||||
* Example usage in a static message table:
|
||||
* @code
|
||||
* struct {
|
||||
* MyClass::VehicleType type;
|
||||
* KLazyLocalizedString msg;
|
||||
* } static constexpr const vehicle_msg_table[] = {
|
||||
* { MyClass::Train, kli18np("%1 train", "%1 trains") },
|
||||
* { MyClass::Bus, kli18ncp("the vehicle, not the USB one", "%1 bus", "%1 buses") },
|
||||
* ...
|
||||
* };
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* const auto it = std::find_if(std::begin(vehicle_msg_table), std::end(vehicle_msg_table), [vehicleType](const auto &m) { return m.type == vehicleType; });
|
||||
* QString translatedMessage = (*it).msg.subs(vehicleCount).toString();
|
||||
* @endcode
|
||||
*
|
||||
* @note KLazyLocalizedString is primarily meant for storage in e.g. message tables,
|
||||
* not for use in API, especially not across translation domains. This is due to
|
||||
* it not carrying the translation domain in which it was created, but using the
|
||||
* active translation domain at the point of converting to a KLocalizedString.
|
||||
*
|
||||
* @since 5.89
|
||||
*/
|
||||
class KLazyLocalizedString
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Construct an empty message.
|
||||
*
|
||||
* Direct construction is used when e.g. a KLazyLocalizedString field in
|
||||
* a data table needs to be set, but there is not message to be used.
|
||||
* Directly constructed instances are not valid for
|
||||
* finalization by \c toString methods.
|
||||
*
|
||||
* \see isEmpty
|
||||
*/
|
||||
constexpr inline KLazyLocalizedString() = default;
|
||||
|
||||
/** Convert to a KLocalizedString to actually perform the translation and obtain a concrete
|
||||
* localized string.
|
||||
*
|
||||
* The translation domain active at this point will be used. This means this has to be
|
||||
* called in the same translation domain the corresponding @c kli18n call is in.
|
||||
*/
|
||||
Q_REQUIRED_RESULT inline operator KLocalizedString() const
|
||||
{
|
||||
if (!m_text) {
|
||||
return KLocalizedString();
|
||||
}
|
||||
#ifdef TRANSLATION_DOMAIN
|
||||
return KLocalizedString(TRANSLATION_DOMAIN, m_context, m_text, m_plural, m_markupAware);
|
||||
#else
|
||||
return KLocalizedString(nullptr, m_context, m_text, m_plural, m_markupAware);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the message is empty.
|
||||
*
|
||||
* The message is considered empty if the object was constructed
|
||||
* via the default constructor.
|
||||
*
|
||||
* Empty messages are not valid for finalization.
|
||||
* The behavior of calling toString() on them is undefined.
|
||||
* In debug mode, an error mark may appear in the returned string.
|
||||
*
|
||||
* \return \c true if the message is empty, \c false otherwise
|
||||
*/
|
||||
Q_REQUIRED_RESULT constexpr inline bool isEmpty() const
|
||||
{
|
||||
return (m_text == nullptr) || (m_text[0] == '\0');
|
||||
}
|
||||
|
||||
/** Returns the raw untranslated text as passed to @p kli18n*. */
|
||||
Q_REQUIRED_RESULT constexpr inline const char *untranslatedText() const
|
||||
{
|
||||
return m_text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalize the translation.
|
||||
*
|
||||
* Creates translated QString. If the string has placeholders,
|
||||
* make sure to call instead \c KLazyLocalizedString::subs and
|
||||
* further \c KLocalizedString::subs methods before finalizing.
|
||||
* Translated text is searched for based on the global locale.
|
||||
*
|
||||
* \return finalized translation
|
||||
*/
|
||||
Q_REQUIRED_RESULT inline QString toString() const
|
||||
{
|
||||
return this->operator KLocalizedString().toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Like toString(), but look for translation only in given languages.
|
||||
*
|
||||
* Given languages override languages defined by the global locale.
|
||||
* If \p languages is empty, original message is returned.
|
||||
*
|
||||
* \param languages list of language codes (by decreasing priority)
|
||||
* \return finalized translation
|
||||
*/
|
||||
Q_REQUIRED_RESULT inline QString toString(const QStringList &languages) const
|
||||
{
|
||||
return this->operator KLocalizedString().toString(languages);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like toString(), but look for translation in the given domain.
|
||||
*
|
||||
* \param domain the translation domain
|
||||
* \return finalized translation
|
||||
*/
|
||||
Q_REQUIRED_RESULT inline QString toString(const char *domain) const
|
||||
{
|
||||
return this->operator KLocalizedString().toString(domain);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like toString(), but resolve KUIT markup into given visual format.
|
||||
*
|
||||
* Given visual format overrides that implied by the context UI marker.
|
||||
* If the message is not markup-aware, this is same as toString().
|
||||
*
|
||||
* \param format the target visual format
|
||||
* \return finalized translation
|
||||
*/
|
||||
Q_REQUIRED_RESULT inline QString toString(Kuit::VisualFormat format) const
|
||||
{
|
||||
return this->operator KLocalizedString().toString(format);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate to look for translation only in given languages.
|
||||
*
|
||||
* \param languages list of language codes (by decreasing priority)
|
||||
* \return updated KLocalizedString
|
||||
*/
|
||||
Q_REQUIRED_RESULT inline KLocalizedString withLanguages(const QStringList &languages) const
|
||||
{
|
||||
return this->operator KLocalizedString().withLanguages(languages);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate to look for translation in the given domain.
|
||||
*
|
||||
* \param domain the translation domain
|
||||
* \return updated KLocalizedString
|
||||
*/
|
||||
Q_REQUIRED_RESULT inline KLocalizedString withDomain(const char *domain) const
|
||||
{
|
||||
return this->operator KLocalizedString().withDomain(domain);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate to resolve KUIT markup into given visual format.
|
||||
*
|
||||
* If the message is not markup-aware, this has no effect.
|
||||
*
|
||||
* \param format the target visual format
|
||||
* \return updated KLocalizedString
|
||||
*/
|
||||
Q_REQUIRED_RESULT inline KLocalizedString withFormat(Kuit::VisualFormat format) const
|
||||
{
|
||||
return this->operator KLocalizedString().withFormat(format);
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitute an int argument into the message.
|
||||
*
|
||||
* \param a the argument
|
||||
* \param fieldWidth width of the formatted field, padded by spaces.
|
||||
* Positive value aligns right, negative aligns left
|
||||
* \param base the radix used to represent the number as a string.
|
||||
* Valid values range from 2 to 36
|
||||
* \param fillChar the character used to fill up the empty places when
|
||||
* field width is greater than argument width
|
||||
* \return updated KLocalizedString
|
||||
*/
|
||||
Q_REQUIRED_RESULT inline KLocalizedString subs(int a, int fieldWidth = 0, int base = 10, QChar fillChar = QLatin1Char(' ')) const
|
||||
{
|
||||
return this->operator KLocalizedString().subs(a, fieldWidth, base, fillChar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitute an unsigned int argument into the message.
|
||||
*
|
||||
* \param a the argument
|
||||
* \param fieldWidth width of the formatted field, padded by spaces.
|
||||
* Positive value aligns right, negative aligns left
|
||||
* \param base the radix used to represent the number as a string.
|
||||
* Valid values range from 2 to 36
|
||||
* \param fillChar the character used to fill up the empty places when
|
||||
* field width is greater than argument width
|
||||
* \return updated KLocalizedString
|
||||
*/
|
||||
Q_REQUIRED_RESULT inline KLocalizedString subs(uint a, int fieldWidth = 0, int base = 10, QChar fillChar = QLatin1Char(' ')) const
|
||||
{
|
||||
return this->operator KLocalizedString().subs(a, fieldWidth, base, fillChar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitute a long argument into the message.
|
||||
*
|
||||
* \param a the argument
|
||||
* \param fieldWidth width of the formatted field, padded by spaces.
|
||||
* Positive value aligns right, negative aligns left
|
||||
* \param base the radix used to represent the number as a string.
|
||||
* Valid values range from 2 to 36
|
||||
* \param fillChar the character used to fill up the empty places when
|
||||
* field width is greater than argument width
|
||||
* \return updated KLocalizedString
|
||||
*/
|
||||
Q_REQUIRED_RESULT inline KLocalizedString subs(long a, int fieldWidth = 0, int base = 10, QChar fillChar = QLatin1Char(' ')) const
|
||||
{
|
||||
return this->operator KLocalizedString().subs(a, fieldWidth, base, fillChar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitute an unsigned long argument into the message.
|
||||
*
|
||||
* \param a the argument
|
||||
* \param fieldWidth width of the formatted field, padded by spaces.
|
||||
* Positive value aligns right, negative aligns left
|
||||
* \param base the radix used to represent the number as a string.
|
||||
* Valid values range from 2 to 36
|
||||
* \param fillChar the character used to fill up the empty places when
|
||||
* field width is greater than argument width
|
||||
* \return updated KLocalizedString
|
||||
*/
|
||||
Q_REQUIRED_RESULT inline KLocalizedString subs(ulong a, int fieldWidth = 0, int base = 10, QChar fillChar = QLatin1Char(' ')) const
|
||||
{
|
||||
return this->operator KLocalizedString().subs(a, fieldWidth, base, fillChar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitute a long long argument into the message.
|
||||
*
|
||||
* \param a the argument
|
||||
* \param fieldWidth width of the formatted field, padded by spaces.
|
||||
* Positive value aligns right, negative aligns left
|
||||
* \param base the radix used to represent the number as a string.
|
||||
* Valid values range from 2 to 36
|
||||
* \param fillChar the character used to fill up the empty places when
|
||||
* field width is greater than argument width
|
||||
* \return updated KLocalizedString
|
||||
*/
|
||||
Q_REQUIRED_RESULT inline KLocalizedString subs(qlonglong a, int fieldWidth = 0, int base = 10, QChar fillChar = QLatin1Char(' ')) const
|
||||
{
|
||||
return this->operator KLocalizedString().subs(a, fieldWidth, base, fillChar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitute an unsigned long long argument into the message.
|
||||
*
|
||||
* \param a the argument
|
||||
* \param fieldWidth width of the formatted field, padded by spaces.
|
||||
* Positive value aligns right, negative aligns left
|
||||
* \param base the radix used to represent the number as a string.
|
||||
* Valid values range from 2 to 36
|
||||
* \param fillChar the character used to fill up the empty places when
|
||||
* field width is greater than argument width
|
||||
* \return updated KLocalizedString
|
||||
*/
|
||||
Q_REQUIRED_RESULT inline KLocalizedString subs(qulonglong a, int fieldWidth = 0, int base = 10, QChar fillChar = QLatin1Char(' ')) const
|
||||
{
|
||||
return this->operator KLocalizedString().subs(a, fieldWidth, base, fillChar);
|
||||
}
|
||||
/**
|
||||
* Substitute a double argument into the message.
|
||||
*
|
||||
* \param a the argument
|
||||
* \param fieldWidth width of the formatted field, padded by spaces.
|
||||
* Positive value aligns right, negative aligns left
|
||||
* \param format type of floating point formatting, like in QString::arg
|
||||
* \param precision number of digits after the decimal separator
|
||||
* \param fillChar the character used to fill up the empty places when
|
||||
* field width is greater than argument width
|
||||
* \return updated KLocalizedString
|
||||
*/
|
||||
Q_REQUIRED_RESULT inline KLocalizedString subs(double a, int fieldWidth = 0, char format = 'g', int precision = -1, QChar fillChar = QLatin1Char(' ')) const
|
||||
{
|
||||
return this->operator KLocalizedString().subs(a, fieldWidth, format, precision, fillChar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitute a \c QChar argument into the message.
|
||||
*
|
||||
* \param a the argument
|
||||
* \param fieldWidth width of the formatted field, padded by spaces.
|
||||
* Positive value aligns right, negative aligns left
|
||||
* \param fillChar the character used to fill up the empty places when
|
||||
* field width is greater than argument width
|
||||
* \return updated KLocalizedString
|
||||
*/
|
||||
Q_REQUIRED_RESULT inline KLocalizedString subs(QChar a, int fieldWidth = 0, QChar fillChar = QLatin1Char(' ')) const
|
||||
{
|
||||
return this->operator KLocalizedString().subs(a, fieldWidth, fillChar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitute a \c QString argument into the message.
|
||||
*
|
||||
* \param a the argument
|
||||
* \param fieldWidth width of the formatted field, padded by spaces.
|
||||
* Positive value aligns right, negative aligns left
|
||||
* \param fillChar the character used to fill up the empty places when
|
||||
* field width is greater than argument width
|
||||
* \return updated KLocalizedString
|
||||
*/
|
||||
Q_REQUIRED_RESULT inline KLocalizedString subs(const QString &a, int fieldWidth = 0, QChar fillChar = QLatin1Char(' ')) const
|
||||
{
|
||||
return this->operator KLocalizedString().subs(a, fieldWidth, fillChar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitute another KLocalizedString into the message.
|
||||
*
|
||||
* \param a the argument
|
||||
* \param fieldWidth width of the formatted field, padded by spaces.
|
||||
* Positive value aligns right, negative aligns left
|
||||
* \param fillChar the character used to fill up the empty places when
|
||||
* field width is greater than argument width
|
||||
* \return updated KLocalizedString
|
||||
*/
|
||||
Q_REQUIRED_RESULT inline KLocalizedString subs(const KLocalizedString &a, int fieldWidth = 0, QChar fillChar = QLatin1Char(' ')) const
|
||||
{
|
||||
return this->operator KLocalizedString().subs(a, fieldWidth, fillChar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add dynamic context to the message.
|
||||
*
|
||||
* See \ref dyn_ctxt for use cases.
|
||||
*
|
||||
* \param key context key
|
||||
* \param value context value
|
||||
* \return updated KLocalizedString
|
||||
*/
|
||||
Q_REQUIRED_RESULT inline KLocalizedString inContext(const QString &key, const QString &value) const
|
||||
{
|
||||
return this->operator KLocalizedString().inContext(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Relax matching between placeholders and arguments.
|
||||
*
|
||||
* Normally the placeholders should start from %1 and have no gaps,
|
||||
* and on finalization there must be exactly as many arguments
|
||||
* supplied through \c subs methods as there are unique plaecholders.
|
||||
* If this is not satisfied, in debug mode warnings are printed
|
||||
* and the finalized string may contain error marks.
|
||||
*
|
||||
* This method relaxes the placeholder-argument matching,
|
||||
* such that there must only be an argument available for
|
||||
* every present unique placeholder (taking placeholder numbers
|
||||
* to be 1-based indices into the argument list).
|
||||
* This can come useful in some situations.
|
||||
*
|
||||
* \return updated KLocalizedString
|
||||
*/
|
||||
Q_REQUIRED_RESULT inline KLocalizedString relaxSubs() const
|
||||
{
|
||||
return this->operator KLocalizedString().relaxSubs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Do not resolve KUIT markup.
|
||||
*
|
||||
* If the message is markup-aware
|
||||
* (constructed by one of \c \*xi18n\* calls),
|
||||
* this function can be used to make it non-markup-aware.
|
||||
* This may be useful for debugging markup.
|
||||
*
|
||||
* \return updated KLocalizedString
|
||||
*/
|
||||
Q_REQUIRED_RESULT inline KLocalizedString ignoreMarkup() const
|
||||
{
|
||||
return this->operator KLocalizedString().ignoreMarkup();
|
||||
}
|
||||
|
||||
private:
|
||||
template<std::size_t TextSize>
|
||||
friend inline constexpr KLazyLocalizedString kli18n(const char (&text)[TextSize]);
|
||||
template<std::size_t ContextSize, std::size_t TextSize>
|
||||
friend constexpr inline KLazyLocalizedString kli18nc(const char (&context)[ContextSize], const char (&text)[TextSize]);
|
||||
template<std::size_t SingularSize, std::size_t PluralSize>
|
||||
friend constexpr inline KLazyLocalizedString kli18np(const char (&singular)[SingularSize], const char (&plural)[PluralSize]);
|
||||
template<std::size_t ContextSize, std::size_t SingularSize, std::size_t PluralSize>
|
||||
friend constexpr inline KLazyLocalizedString
|
||||
kli18ncp(const char (&context)[ContextSize], const char (&singular)[SingularSize], const char (&plural)[PluralSize]);
|
||||
template<std::size_t TextSize>
|
||||
friend constexpr inline KLazyLocalizedString klxi18n(const char (&text)[TextSize]);
|
||||
template<std::size_t ContextSize, std::size_t TextSize>
|
||||
friend constexpr inline KLazyLocalizedString klxi18nc(const char (&context)[ContextSize], const char (&text)[TextSize]);
|
||||
template<std::size_t SingularSize, std::size_t PluralSize>
|
||||
friend constexpr inline KLazyLocalizedString klxi18np(const char (&singular)[SingularSize], const char (&plural)[PluralSize]);
|
||||
template<std::size_t ContextSize, std::size_t SingularSize, std::size_t PluralSize>
|
||||
friend constexpr inline KLazyLocalizedString
|
||||
klxi18ncp(const char (&context)[ContextSize], const char (&singular)[SingularSize], const char (&plural)[PluralSize]);
|
||||
|
||||
constexpr inline KLazyLocalizedString(const char *context, const char *text, const char *plural, bool markupAware)
|
||||
: m_context(context)
|
||||
, m_text(text)
|
||||
, m_plural(plural)
|
||||
, m_markupAware(markupAware)
|
||||
{
|
||||
}
|
||||
|
||||
const char *m_context = nullptr;
|
||||
const char *m_text = nullptr;
|
||||
const char *m_plural = nullptr;
|
||||
bool m_markupAware = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Mark the string @p text for extraction.
|
||||
*
|
||||
* \param text string to translate
|
||||
* \return KLazyLocalizedString for deferred translation.
|
||||
* \since 5.89
|
||||
*/
|
||||
template<std::size_t TextSize>
|
||||
constexpr inline KLazyLocalizedString kli18n(const char (&text)[TextSize])
|
||||
{
|
||||
return KLazyLocalizedString(nullptr, text, nullptr, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the string @p text with @p context for extraction.
|
||||
*
|
||||
* \param context context of the string
|
||||
* \param text string to translate
|
||||
* \return KLazyLocalizedString for deferred translation.
|
||||
* \since 5.89
|
||||
*/
|
||||
template<std::size_t ContextSize, std::size_t TextSize>
|
||||
constexpr inline KLazyLocalizedString kli18nc(const char (&context)[ContextSize], const char (&text)[TextSize])
|
||||
{
|
||||
return KLazyLocalizedString(context, text, nullptr, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the string @p singular and @p plural for extraction.
|
||||
*
|
||||
* \param singular singular form of the string to translate
|
||||
* \param plural plural form of the string to translate
|
||||
* \return KLazyLocalizedString for deferred translation.
|
||||
* \since 5.89
|
||||
*/
|
||||
template<std::size_t SingularSize, std::size_t PluralSize>
|
||||
constexpr inline KLazyLocalizedString kli18np(const char (&singular)[SingularSize], const char (&plural)[PluralSize])
|
||||
{
|
||||
return KLazyLocalizedString(nullptr, singular, plural, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the string @p singular and @p plural with @p context for extraction.
|
||||
*
|
||||
* \param context context of the string
|
||||
* \param singular singular form of the string to translate
|
||||
* \param plural plural form of the string to translate
|
||||
* \return KLazyLocalizedString for deferred translation.
|
||||
* \since 5.89
|
||||
*/
|
||||
template<std::size_t ContextSize, std::size_t SingularSize, std::size_t PluralSize>
|
||||
constexpr inline KLazyLocalizedString kli18ncp(const char (&context)[ContextSize], const char (&singular)[SingularSize], const char (&plural)[PluralSize])
|
||||
{
|
||||
return KLazyLocalizedString(context, singular, plural, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the markup-aware string @p text for extraction.
|
||||
*
|
||||
* \param text string to translate
|
||||
* \return KLazyLocalizedString for deferred translation.
|
||||
* \since 5.89
|
||||
*/
|
||||
template<std::size_t TextSize>
|
||||
constexpr inline KLazyLocalizedString klxi18n(const char (&text)[TextSize])
|
||||
{
|
||||
return KLazyLocalizedString(nullptr, text, nullptr, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the markup-aware string @p text with @p context for extraction.
|
||||
*
|
||||
* \param context context of the string
|
||||
* \param text string to translate
|
||||
* \return KLazyLocalizedString for deferred translation.
|
||||
* \since 5.89
|
||||
*/
|
||||
template<std::size_t ContextSize, std::size_t TextSize>
|
||||
constexpr inline KLazyLocalizedString klxi18nc(const char (&context)[ContextSize], const char (&text)[TextSize])
|
||||
{
|
||||
return KLazyLocalizedString(context, text, nullptr, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the markup-aware string @p singular and @p plural for extraction.
|
||||
*
|
||||
* \param singular singular form of the string to translate
|
||||
* \param plural plural form of the string to translate
|
||||
* \return KLazyLocalizedString for deferred translation.
|
||||
* \since 5.89
|
||||
*/
|
||||
template<std::size_t SingularSize, std::size_t PluralSize>
|
||||
constexpr inline KLazyLocalizedString klxi18np(const char (&singular)[SingularSize], const char (&plural)[PluralSize])
|
||||
{
|
||||
return KLazyLocalizedString(nullptr, singular, plural, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the markup-aware string @p singular and @p plural with @p context for extraction.
|
||||
*
|
||||
* \param context context of the string
|
||||
* \param singular singular form of the string to translate
|
||||
* \param plural plural form of the string to translate
|
||||
* \return KLazyLocalizedString for deferred translation.
|
||||
* \since 5.89
|
||||
*/
|
||||
template<std::size_t ContextSize, std::size_t SingularSize, std::size_t PluralSize>
|
||||
constexpr inline KLazyLocalizedString klxi18ncp(const char (&context)[ContextSize], const char (&singular)[SingularSize], const char (&plural)[PluralSize])
|
||||
{
|
||||
return KLazyLocalizedString(context, singular, plural, true);
|
||||
}
|
||||
|
||||
#endif // KLAZYLOCALIZEDSTRING_H
|
||||
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2024 Lukas Sommer <sommerluk@gmail.com>
|
||||
SPDX-FileCopyrightText: 2024 Volker Krause <vkrause@kde.org>
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "klocalization.h"
|
||||
|
||||
// this file only exists so we check klocalization.h compiles
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2024 Lukas Sommer <sommerluk@gmail.com>
|
||||
SPDX-FileCopyrightText: 2024 Volker Krause <vkrause@kde.org>
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef KLOCALIZATION_H
|
||||
#define KLOCALIZATION_H
|
||||
|
||||
#include "klocalizedstring.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QVariant>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
class QDoubleSpinBox;
|
||||
class QSpinBox;
|
||||
|
||||
/**
|
||||
* @namespace KLocalization
|
||||
* @brief Namespace containing helpers for localization.
|
||||
* @since 6.5
|
||||
*/
|
||||
namespace KLocalization
|
||||
{
|
||||
|
||||
///@cond hidden
|
||||
namespace Private
|
||||
{
|
||||
|
||||
constexpr inline const char SpinBoxFormatStringProperty[] = "__KLocalizationFormatStringPrivate";
|
||||
|
||||
}
|
||||
///@endcond
|
||||
|
||||
/**
|
||||
* @brief Retranslates a previously set up format string to the current
|
||||
* language and updates the spin box.
|
||||
*
|
||||
* The format string is initially set up by setupSpinBoxFormatString().
|
||||
* This function updates the prefix and suffix of a spin box to reflect the
|
||||
* current language settings. It is useful for responding to language changes,
|
||||
* such as those triggered by QEvent::LanguageChange.
|
||||
*
|
||||
* @tparam T The type of the spin box, which must be either QSpinBox or
|
||||
* QDoubleSpinBox.
|
||||
* @param spinBox Pointer to the spin box.
|
||||
*
|
||||
* @post The prefix and suffix of the spin box are updated to reflect the
|
||||
* current language.
|
||||
*
|
||||
* @sa @ref setupSpinBoxFormatString
|
||||
*
|
||||
* @since 6.5
|
||||
*/
|
||||
|
||||
template<typename T>
|
||||
inline void retranslateSpinBoxFormatString(T *spinBox)
|
||||
{
|
||||
constexpr bool isSpinBox = std::is_base_of_v<QSpinBox, T> || std::is_base_of_v<QDoubleSpinBox, T>;
|
||||
static_assert(isSpinBox, "First argument must be a QSpinBox or QDoubleSpinBox.");
|
||||
|
||||
const auto lString = spinBox->property(Private::SpinBoxFormatStringProperty).template value<KLocalizedString>();
|
||||
// The KLocalizedString::subs() method performs two tasks:
|
||||
// 1. It replaces placeholders (%1, %2, ...) in the string with actual
|
||||
// content.
|
||||
// 2. If the argument is an integer, it selects the appropriate plural form
|
||||
// based on the value.
|
||||
// In this context, the string is expected not to contain any standard
|
||||
// placeholders (%1, %2, ...). Instead, it should contain a custom
|
||||
// placeholder (%v) which is ignored by KLocalizedString::subs().
|
||||
// The only purpose of calling KLocalizedString::subs() here is to ensure
|
||||
// the correct plural form is used when spinBox->value() is an integer.
|
||||
// If spinBox->value() is a double, KLocalizedString::subs() does not
|
||||
// perform any operations on the string since plural handling applies only
|
||||
// to integer values.
|
||||
const auto translation = lString.subs(spinBox->value()).toString();
|
||||
const auto parts = translation.split(QLatin1StringView("%v"));
|
||||
if (parts.count() == 2) {
|
||||
spinBox->setPrefix(parts.at(0));
|
||||
spinBox->setSuffix(parts.at(1));
|
||||
} else {
|
||||
spinBox->setPrefix(QString());
|
||||
spinBox->setSuffix(QString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets up a format string for internationalizing spin boxes.
|
||||
*
|
||||
* This function allows the customization of prefix and suffix for spin boxes
|
||||
* (QSpinBox and QDoubleSpinBox), considering internationalization needs.
|
||||
*
|
||||
* Spin boxes display a number and possibly a prefix and/or suffix. However,
|
||||
* in some languages, the position of the prefix and suffix may be reversed
|
||||
* compared to English. Example: In English, you write 50%, but in Turkish,
|
||||
* you write %50. Qt does not offer an out-of-the-box solution for this. This
|
||||
* helper now provides complete internationalization for prefixes and suffixes
|
||||
* of spin boxes.
|
||||
*
|
||||
* For QSpinBox it also provides correct plural handling by installing a
|
||||
* handler for the valueChanged() signal to update prefix and suffix whenever
|
||||
* the spin box value changes in the future.
|
||||
*
|
||||
* Example usage:
|
||||
* @code
|
||||
* QDoubleSpinBox doubleBox;
|
||||
* KLocalization::setupSpinBoxFormatString(
|
||||
* &doubleBox,
|
||||
* ki18nc("@item %v is a number and the second % is the percent sign", "%v%"));
|
||||
* // Turkish translation: "%%v"
|
||||
*
|
||||
* QSpinBox intBox;
|
||||
* KLocalization::setupSpinBoxFormatString(
|
||||
* &intBox,
|
||||
* ki18ncp("@item %v is a number", "Baking %v cake", "Baking %v cakes"));
|
||||
* @endcode
|
||||
*
|
||||
* @tparam T The type of the spin box, which must be either QSpinBox or QDoubleSpinBox.
|
||||
* @param spinBox Pointer to the spin box.
|
||||
* @param formatString A localized string in the format "PREFIX%vSUFFIX".
|
||||
* - For QDoubleSpinBox, plural forms in @p formatString are ignored
|
||||
* and should be avoided. Use @ref KLocalizedString::ki18nc "ki18nc()"
|
||||
* to generate the format string.
|
||||
* - For QSpinBox, if @p formatString includes plural forms, they are
|
||||
* utilized. While optional, their use is highly recommended for
|
||||
* accurate pluralization. Use @ref KLocalizedString::ki18ncp "ki18ncp()"
|
||||
* to generate the format string.
|
||||
*
|
||||
* @note It is safe to call this function multiple times on the same spin box.
|
||||
*
|
||||
* @sa @ref retranslateSpinBoxFormatString
|
||||
*
|
||||
* @since 6.5
|
||||
*/
|
||||
|
||||
template<typename T>
|
||||
inline void setupSpinBoxFormatString(T *spinBox, const KLocalizedString &formatString)
|
||||
{
|
||||
constexpr bool isSpinBox = std::is_base_of_v<QSpinBox, T>;
|
||||
constexpr bool isDoubleSpinBox = std::is_base_of_v<QDoubleSpinBox, T>;
|
||||
static_assert(isSpinBox || isDoubleSpinBox, "First argument must be a QSpinBox or QDoubleSpinBox.");
|
||||
|
||||
if constexpr (isSpinBox) {
|
||||
const bool hasSetup = !spinBox->property(Private::SpinBoxFormatStringProperty).isNull();
|
||||
if (!hasSetup) {
|
||||
QObject::connect(spinBox, &T::valueChanged, spinBox, [spinBox]() {
|
||||
retranslateSpinBoxFormatString(spinBox);
|
||||
});
|
||||
}
|
||||
}
|
||||
// Using relaxSubs() to avoid error marks if the library user did pass
|
||||
// a singular-only KLocalizedString.
|
||||
spinBox->setProperty(Private::SpinBoxFormatStringProperty, QVariant::fromValue(formatString.relaxSubs()));
|
||||
retranslateSpinBoxFormatString(spinBox);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,584 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
// Undefine this because we don't want our i18n*() method names to be turned into i18nd*()
|
||||
#undef TRANSLATION_DOMAIN
|
||||
|
||||
#include "klocalizedcontext.h"
|
||||
|
||||
#if KI18N_BUILD_DEPRECATED_SINCE(6, 8)
|
||||
#include <klocalizedstring.h>
|
||||
|
||||
#include "ki18n_logging.h"
|
||||
|
||||
class KLocalizedContextPrivate
|
||||
{
|
||||
public:
|
||||
QString m_translationDomain;
|
||||
};
|
||||
|
||||
KLocalizedContext::KLocalizedContext(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new KLocalizedContextPrivate)
|
||||
{
|
||||
}
|
||||
|
||||
KLocalizedContext::~KLocalizedContext()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
QString KLocalizedContext::translationDomain() const
|
||||
{
|
||||
return d->m_translationDomain;
|
||||
}
|
||||
|
||||
void KLocalizedContext::setTranslationDomain(const QString &domain)
|
||||
{
|
||||
if (domain != d->m_translationDomain) {
|
||||
d->m_translationDomain = domain;
|
||||
Q_EMIT translationDomainChanged(domain);
|
||||
}
|
||||
}
|
||||
|
||||
static void subsVariant(KLocalizedString &trMessage, const QVariant &value)
|
||||
{
|
||||
switch (value.userType()) {
|
||||
case QMetaType::QString:
|
||||
trMessage = trMessage.subs(value.toString());
|
||||
break;
|
||||
case QMetaType::Int:
|
||||
trMessage = trMessage.subs(value.toInt());
|
||||
break;
|
||||
case QMetaType::Double:
|
||||
trMessage = trMessage.subs(value.toDouble());
|
||||
break;
|
||||
case QMetaType::Char:
|
||||
trMessage = trMessage.subs(value.toChar());
|
||||
break;
|
||||
default:
|
||||
if (value.canConvert<QString>()) {
|
||||
trMessage = trMessage.subs(value.toString());
|
||||
} else {
|
||||
trMessage = trMessage.subs(QStringLiteral("???"));
|
||||
qCWarning(KI18N) << "couldn't convert" << value << "to translate";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void resolveMessage(KLocalizedString &trMessage,
|
||||
const QVariant ¶m1,
|
||||
const QVariant ¶m2,
|
||||
const QVariant ¶m3,
|
||||
const QVariant ¶m4,
|
||||
const QVariant ¶m5,
|
||||
const QVariant ¶m6,
|
||||
const QVariant ¶m7,
|
||||
const QVariant ¶m8,
|
||||
const QVariant ¶m9,
|
||||
const QVariant ¶m10 = QVariant())
|
||||
{
|
||||
if (param1.isValid()) {
|
||||
subsVariant(trMessage, param1);
|
||||
}
|
||||
if (param2.isValid()) {
|
||||
subsVariant(trMessage, param2);
|
||||
}
|
||||
if (param3.isValid()) {
|
||||
subsVariant(trMessage, param3);
|
||||
}
|
||||
if (param4.isValid()) {
|
||||
subsVariant(trMessage, param4);
|
||||
}
|
||||
if (param5.isValid()) {
|
||||
subsVariant(trMessage, param5);
|
||||
}
|
||||
if (param6.isValid()) {
|
||||
subsVariant(trMessage, param6);
|
||||
}
|
||||
if (param7.isValid()) {
|
||||
subsVariant(trMessage, param7);
|
||||
}
|
||||
if (param8.isValid()) {
|
||||
subsVariant(trMessage, param8);
|
||||
}
|
||||
if (param9.isValid()) {
|
||||
subsVariant(trMessage, param9);
|
||||
}
|
||||
if (param10.isValid()) {
|
||||
subsVariant(trMessage, param10);
|
||||
}
|
||||
}
|
||||
|
||||
static void resolvePlural(KLocalizedString &trMessage, const QVariant ¶m)
|
||||
{
|
||||
trMessage = trMessage.subs(param.toInt());
|
||||
}
|
||||
|
||||
QString KLocalizedContext::i18n(const QString &message,
|
||||
const QVariant ¶m1,
|
||||
const QVariant ¶m2,
|
||||
const QVariant ¶m3,
|
||||
const QVariant ¶m4,
|
||||
const QVariant ¶m5,
|
||||
const QVariant ¶m6,
|
||||
const QVariant ¶m7,
|
||||
const QVariant ¶m8,
|
||||
const QVariant ¶m9,
|
||||
const QVariant ¶m10) const
|
||||
{
|
||||
if (message.isEmpty()) {
|
||||
qCWarning(KI18N) << "i18n() needs at least one parameter";
|
||||
return QString();
|
||||
}
|
||||
|
||||
KLocalizedString trMessage;
|
||||
if (!d->m_translationDomain.isEmpty()) {
|
||||
trMessage = ki18nd(d->m_translationDomain.toUtf8().constData(), message.toUtf8().constData());
|
||||
} else {
|
||||
trMessage = ki18n(message.toUtf8().constData());
|
||||
}
|
||||
|
||||
resolveMessage(trMessage, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10);
|
||||
|
||||
return trMessage.toString();
|
||||
}
|
||||
|
||||
QString KLocalizedContext::i18nc(const QString &context,
|
||||
const QString &message,
|
||||
const QVariant ¶m1,
|
||||
const QVariant ¶m2,
|
||||
const QVariant ¶m3,
|
||||
const QVariant ¶m4,
|
||||
const QVariant ¶m5,
|
||||
const QVariant ¶m6,
|
||||
const QVariant ¶m7,
|
||||
const QVariant ¶m8,
|
||||
const QVariant ¶m9,
|
||||
const QVariant ¶m10) const
|
||||
{
|
||||
if (context.isEmpty() || message.isEmpty()) {
|
||||
qCWarning(KI18N) << "i18nc() needs at least two arguments";
|
||||
return QString();
|
||||
}
|
||||
|
||||
KLocalizedString trMessage;
|
||||
if (!d->m_translationDomain.isEmpty()) {
|
||||
trMessage = ki18ndc(d->m_translationDomain.toUtf8().constData(), context.toUtf8().constData(), message.toUtf8().constData());
|
||||
} else {
|
||||
trMessage = ki18nc(context.toUtf8().constData(), message.toUtf8().constData());
|
||||
}
|
||||
|
||||
resolveMessage(trMessage, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10);
|
||||
|
||||
return trMessage.toString();
|
||||
}
|
||||
|
||||
QString KLocalizedContext::i18np(const QString &singular,
|
||||
const QString &plural,
|
||||
const QVariant ¶m1,
|
||||
const QVariant ¶m2,
|
||||
const QVariant ¶m3,
|
||||
const QVariant ¶m4,
|
||||
const QVariant ¶m5,
|
||||
const QVariant ¶m6,
|
||||
const QVariant ¶m7,
|
||||
const QVariant ¶m8,
|
||||
const QVariant ¶m9,
|
||||
const QVariant ¶m10) const
|
||||
{
|
||||
if (singular.isEmpty() || plural.isEmpty()) {
|
||||
qCWarning(KI18N) << "i18np() needs at least two arguments";
|
||||
return QString();
|
||||
}
|
||||
|
||||
KLocalizedString trMessage;
|
||||
if (!d->m_translationDomain.isEmpty()) {
|
||||
trMessage = ki18ndp(d->m_translationDomain.toUtf8().constData(), singular.toUtf8().constData(), plural.toUtf8().constData());
|
||||
} else {
|
||||
trMessage = ki18np(singular.toUtf8().constData(), plural.toUtf8().constData());
|
||||
}
|
||||
|
||||
resolvePlural(trMessage, param1);
|
||||
resolveMessage(trMessage, param2, param3, param4, param5, param6, param7, param8, param9, param10);
|
||||
|
||||
return trMessage.toString();
|
||||
}
|
||||
|
||||
QString KLocalizedContext::i18ncp(const QString &context,
|
||||
const QString &singular,
|
||||
const QString &plural,
|
||||
const QVariant ¶m1,
|
||||
const QVariant ¶m2,
|
||||
const QVariant ¶m3,
|
||||
const QVariant ¶m4,
|
||||
const QVariant ¶m5,
|
||||
const QVariant ¶m6,
|
||||
const QVariant ¶m7,
|
||||
const QVariant ¶m8,
|
||||
const QVariant ¶m9,
|
||||
const QVariant ¶m10) const
|
||||
{
|
||||
if (context.isEmpty() || singular.isEmpty() || plural.isEmpty()) {
|
||||
qCWarning(KI18N) << "i18ncp() needs at least three arguments";
|
||||
return QString();
|
||||
}
|
||||
|
||||
KLocalizedString trMessage;
|
||||
if (!d->m_translationDomain.isEmpty()) {
|
||||
trMessage =
|
||||
ki18ndcp(d->m_translationDomain.toUtf8().constData(), context.toUtf8().constData(), singular.toUtf8().constData(), plural.toUtf8().constData());
|
||||
} else {
|
||||
trMessage = ki18ncp(context.toUtf8().constData(), singular.toUtf8().constData(), plural.toUtf8().constData());
|
||||
}
|
||||
|
||||
resolvePlural(trMessage, param1);
|
||||
resolveMessage(trMessage, param2, param3, param4, param5, param6, param7, param8, param9, param10);
|
||||
|
||||
return trMessage.toString();
|
||||
}
|
||||
|
||||
QString KLocalizedContext::i18nd(const QString &domain,
|
||||
const QString &message,
|
||||
const QVariant ¶m1,
|
||||
const QVariant ¶m2,
|
||||
const QVariant ¶m3,
|
||||
const QVariant ¶m4,
|
||||
const QVariant ¶m5,
|
||||
const QVariant ¶m6,
|
||||
const QVariant ¶m7,
|
||||
const QVariant ¶m8,
|
||||
const QVariant ¶m9,
|
||||
const QVariant ¶m10) const
|
||||
{
|
||||
if (domain.isEmpty() || message.isEmpty()) {
|
||||
qCWarning(KI18N) << "i18nd() needs at least two parameters";
|
||||
return QString();
|
||||
}
|
||||
|
||||
KLocalizedString trMessage = ki18nd(domain.toUtf8().constData(), message.toUtf8().constData());
|
||||
|
||||
resolveMessage(trMessage, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10);
|
||||
|
||||
return trMessage.toString();
|
||||
}
|
||||
|
||||
QString KLocalizedContext::i18ndc(const QString &domain,
|
||||
const QString &context,
|
||||
const QString &message,
|
||||
const QVariant ¶m1,
|
||||
const QVariant ¶m2,
|
||||
const QVariant ¶m3,
|
||||
const QVariant ¶m4,
|
||||
const QVariant ¶m5,
|
||||
const QVariant ¶m6,
|
||||
const QVariant ¶m7,
|
||||
const QVariant ¶m8,
|
||||
const QVariant ¶m9,
|
||||
const QVariant ¶m10) const
|
||||
{
|
||||
if (domain.isEmpty() || context.isEmpty() || message.isEmpty()) {
|
||||
qCWarning(KI18N) << "i18ndc() needs at least three arguments";
|
||||
return QString();
|
||||
}
|
||||
|
||||
KLocalizedString trMessage = ki18ndc(domain.toUtf8().constData(), context.toUtf8().constData(), message.toUtf8().constData());
|
||||
|
||||
resolveMessage(trMessage, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10);
|
||||
|
||||
return trMessage.toString();
|
||||
}
|
||||
|
||||
QString KLocalizedContext::i18ndp(const QString &domain,
|
||||
const QString &singular,
|
||||
const QString &plural,
|
||||
const QVariant ¶m1,
|
||||
const QVariant ¶m2,
|
||||
const QVariant ¶m3,
|
||||
const QVariant ¶m4,
|
||||
const QVariant ¶m5,
|
||||
const QVariant ¶m6,
|
||||
const QVariant ¶m7,
|
||||
const QVariant ¶m8,
|
||||
const QVariant ¶m9,
|
||||
const QVariant ¶m10) const
|
||||
{
|
||||
if (domain.isEmpty() || singular.isEmpty() || plural.isEmpty()) {
|
||||
qCWarning(KI18N) << "i18ndp() needs at least three arguments";
|
||||
return QString();
|
||||
}
|
||||
|
||||
KLocalizedString trMessage = ki18ndp(domain.toUtf8().constData(), singular.toUtf8().constData(), plural.toUtf8().constData());
|
||||
|
||||
resolvePlural(trMessage, param1);
|
||||
resolveMessage(trMessage, param2, param3, param4, param5, param6, param7, param8, param9, param10);
|
||||
|
||||
return trMessage.toString();
|
||||
}
|
||||
|
||||
QString KLocalizedContext::i18ndcp(const QString &domain,
|
||||
const QString &context,
|
||||
const QString &singular,
|
||||
const QString &plural,
|
||||
const QVariant ¶m1,
|
||||
const QVariant ¶m2,
|
||||
const QVariant ¶m3,
|
||||
const QVariant ¶m4,
|
||||
const QVariant ¶m5,
|
||||
const QVariant ¶m6,
|
||||
const QVariant ¶m7,
|
||||
const QVariant ¶m8,
|
||||
const QVariant ¶m9,
|
||||
const QVariant ¶m10) const
|
||||
{
|
||||
if (domain.isEmpty() || context.isEmpty() || singular.isEmpty() || plural.isEmpty()) {
|
||||
qCWarning(KI18N) << "i18ndcp() needs at least four arguments";
|
||||
return QString();
|
||||
}
|
||||
|
||||
KLocalizedString trMessage =
|
||||
ki18ndcp(domain.toUtf8().constData(), context.toUtf8().constData(), singular.toUtf8().constData(), plural.toUtf8().constData());
|
||||
|
||||
resolvePlural(trMessage, param1);
|
||||
resolveMessage(trMessage, param2, param3, param4, param5, param6, param7, param8, param9, param10);
|
||||
|
||||
return trMessage.toString();
|
||||
}
|
||||
|
||||
/////////////////////////
|
||||
|
||||
QString KLocalizedContext::xi18n(const QString &message,
|
||||
const QVariant ¶m1,
|
||||
const QVariant ¶m2,
|
||||
const QVariant ¶m3,
|
||||
const QVariant ¶m4,
|
||||
const QVariant ¶m5,
|
||||
const QVariant ¶m6,
|
||||
const QVariant ¶m7,
|
||||
const QVariant ¶m8,
|
||||
const QVariant ¶m9,
|
||||
const QVariant ¶m10) const
|
||||
{
|
||||
if (message.isEmpty()) {
|
||||
qCWarning(KI18N) << "xi18n() needs at least one parameter";
|
||||
return QString();
|
||||
}
|
||||
|
||||
KLocalizedString trMessage;
|
||||
if (!d->m_translationDomain.isEmpty()) {
|
||||
trMessage = kxi18nd(d->m_translationDomain.toUtf8().constData(), message.toUtf8().constData());
|
||||
} else {
|
||||
trMessage = kxi18n(message.toUtf8().constData());
|
||||
}
|
||||
|
||||
resolveMessage(trMessage, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10);
|
||||
|
||||
return trMessage.toString();
|
||||
}
|
||||
|
||||
QString KLocalizedContext::xi18nc(const QString &context,
|
||||
const QString &message,
|
||||
const QVariant ¶m1,
|
||||
const QVariant ¶m2,
|
||||
const QVariant ¶m3,
|
||||
const QVariant ¶m4,
|
||||
const QVariant ¶m5,
|
||||
const QVariant ¶m6,
|
||||
const QVariant ¶m7,
|
||||
const QVariant ¶m8,
|
||||
const QVariant ¶m9,
|
||||
const QVariant ¶m10) const
|
||||
{
|
||||
if (context.isEmpty() || message.isEmpty()) {
|
||||
qCWarning(KI18N) << "xi18nc() needs at least two arguments";
|
||||
return QString();
|
||||
}
|
||||
|
||||
KLocalizedString trMessage;
|
||||
if (!d->m_translationDomain.isEmpty()) {
|
||||
trMessage = kxi18ndc(d->m_translationDomain.toUtf8().constData(), context.toUtf8().constData(), message.toUtf8().constData());
|
||||
} else {
|
||||
trMessage = kxi18nc(context.toUtf8().constData(), message.toUtf8().constData());
|
||||
}
|
||||
|
||||
resolveMessage(trMessage, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10);
|
||||
|
||||
return trMessage.toString();
|
||||
}
|
||||
|
||||
QString KLocalizedContext::xi18np(const QString &singular,
|
||||
const QString &plural,
|
||||
const QVariant ¶m1,
|
||||
const QVariant ¶m2,
|
||||
const QVariant ¶m3,
|
||||
const QVariant ¶m4,
|
||||
const QVariant ¶m5,
|
||||
const QVariant ¶m6,
|
||||
const QVariant ¶m7,
|
||||
const QVariant ¶m8,
|
||||
const QVariant ¶m9,
|
||||
const QVariant ¶m10) const
|
||||
{
|
||||
if (singular.isEmpty() || plural.isEmpty()) {
|
||||
qCWarning(KI18N) << "xi18np() needs at least two arguments";
|
||||
return QString();
|
||||
}
|
||||
|
||||
KLocalizedString trMessage;
|
||||
if (!d->m_translationDomain.isEmpty()) {
|
||||
trMessage = kxi18ndp(d->m_translationDomain.toUtf8().constData(), singular.toUtf8().constData(), plural.toUtf8().constData());
|
||||
} else {
|
||||
trMessage = kxi18np(singular.toUtf8().constData(), plural.toUtf8().constData());
|
||||
}
|
||||
|
||||
resolvePlural(trMessage, param1);
|
||||
resolveMessage(trMessage, param2, param3, param4, param5, param6, param7, param8, param9, param10);
|
||||
|
||||
return trMessage.toString();
|
||||
}
|
||||
|
||||
QString KLocalizedContext::xi18ncp(const QString &context,
|
||||
const QString &singular,
|
||||
const QString &plural,
|
||||
const QVariant ¶m1,
|
||||
const QVariant ¶m2,
|
||||
const QVariant ¶m3,
|
||||
const QVariant ¶m4,
|
||||
const QVariant ¶m5,
|
||||
const QVariant ¶m6,
|
||||
const QVariant ¶m7,
|
||||
const QVariant ¶m8,
|
||||
const QVariant ¶m9,
|
||||
const QVariant ¶m10) const
|
||||
{
|
||||
if (context.isEmpty() || singular.isEmpty() || plural.isEmpty()) {
|
||||
qCWarning(KI18N) << "xi18ncp() needs at least three arguments";
|
||||
return QString();
|
||||
}
|
||||
|
||||
KLocalizedString trMessage;
|
||||
if (!d->m_translationDomain.isEmpty()) {
|
||||
trMessage =
|
||||
kxi18ndcp(d->m_translationDomain.toUtf8().constData(), context.toUtf8().constData(), singular.toUtf8().constData(), plural.toUtf8().constData());
|
||||
} else {
|
||||
trMessage = kxi18ncp(context.toUtf8().constData(), singular.toUtf8().constData(), plural.toUtf8().constData());
|
||||
}
|
||||
|
||||
resolvePlural(trMessage, param1);
|
||||
resolveMessage(trMessage, param2, param3, param4, param5, param6, param7, param8, param9, param10);
|
||||
|
||||
return trMessage.toString();
|
||||
}
|
||||
|
||||
QString KLocalizedContext::xi18nd(const QString &domain,
|
||||
const QString &message,
|
||||
const QVariant ¶m1,
|
||||
const QVariant ¶m2,
|
||||
const QVariant ¶m3,
|
||||
const QVariant ¶m4,
|
||||
const QVariant ¶m5,
|
||||
const QVariant ¶m6,
|
||||
const QVariant ¶m7,
|
||||
const QVariant ¶m8,
|
||||
const QVariant ¶m9,
|
||||
const QVariant ¶m10) const
|
||||
{
|
||||
if (domain.isEmpty() || message.isEmpty()) {
|
||||
qCWarning(KI18N) << "xi18nd() needs at least two parameters";
|
||||
return QString();
|
||||
}
|
||||
|
||||
KLocalizedString trMessage = kxi18nd(domain.toUtf8().constData(), message.toUtf8().constData());
|
||||
|
||||
resolveMessage(trMessage, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10);
|
||||
|
||||
return trMessage.toString();
|
||||
}
|
||||
|
||||
QString KLocalizedContext::xi18ndc(const QString &domain,
|
||||
const QString &context,
|
||||
const QString &message,
|
||||
const QVariant ¶m1,
|
||||
const QVariant ¶m2,
|
||||
const QVariant ¶m3,
|
||||
const QVariant ¶m4,
|
||||
const QVariant ¶m5,
|
||||
const QVariant ¶m6,
|
||||
const QVariant ¶m7,
|
||||
const QVariant ¶m8,
|
||||
const QVariant ¶m9,
|
||||
const QVariant ¶m10) const
|
||||
{
|
||||
if (domain.isEmpty() || context.isEmpty() || message.isEmpty()) {
|
||||
qCWarning(KI18N) << "x18ndc() needs at least three arguments";
|
||||
return QString();
|
||||
}
|
||||
|
||||
KLocalizedString trMessage = kxi18ndc(domain.toUtf8().constData(), context.toUtf8().constData(), message.toUtf8().constData());
|
||||
|
||||
resolveMessage(trMessage, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10);
|
||||
|
||||
return trMessage.toString();
|
||||
}
|
||||
|
||||
QString KLocalizedContext::xi18ndp(const QString &domain,
|
||||
const QString &singular,
|
||||
const QString &plural,
|
||||
const QVariant ¶m1,
|
||||
const QVariant ¶m2,
|
||||
const QVariant ¶m3,
|
||||
const QVariant ¶m4,
|
||||
const QVariant ¶m5,
|
||||
const QVariant ¶m6,
|
||||
const QVariant ¶m7,
|
||||
const QVariant ¶m8,
|
||||
const QVariant ¶m9,
|
||||
const QVariant ¶m10) const
|
||||
{
|
||||
if (domain.isEmpty() || singular.isEmpty() || plural.isEmpty()) {
|
||||
qCWarning(KI18N) << "xi18ndp() needs at least three arguments";
|
||||
return QString();
|
||||
}
|
||||
|
||||
KLocalizedString trMessage = kxi18ndp(domain.toUtf8().constData(), singular.toUtf8().constData(), plural.toUtf8().constData());
|
||||
|
||||
resolvePlural(trMessage, param1);
|
||||
resolveMessage(trMessage, param2, param3, param4, param5, param6, param7, param8, param9, param10);
|
||||
|
||||
return trMessage.toString();
|
||||
}
|
||||
|
||||
QString KLocalizedContext::xi18ndcp(const QString &domain,
|
||||
const QString &context,
|
||||
const QString &singular,
|
||||
const QString &plural,
|
||||
const QVariant ¶m1,
|
||||
const QVariant ¶m2,
|
||||
const QVariant ¶m3,
|
||||
const QVariant ¶m4,
|
||||
const QVariant ¶m5,
|
||||
const QVariant ¶m6,
|
||||
const QVariant ¶m7,
|
||||
const QVariant ¶m8,
|
||||
const QVariant ¶m9,
|
||||
const QVariant ¶m10) const
|
||||
{
|
||||
if (domain.isEmpty() || context.isEmpty() || singular.isEmpty() || plural.isEmpty()) {
|
||||
qCWarning(KI18N) << "xi18ndcp() needs at least four arguments";
|
||||
return QString();
|
||||
}
|
||||
|
||||
KLocalizedString trMessage =
|
||||
kxi18ndcp(domain.toUtf8().constData(), context.toUtf8().constData(), singular.toUtf8().constData(), plural.toUtf8().constData());
|
||||
|
||||
resolvePlural(trMessage, param1);
|
||||
resolveMessage(trMessage, param2, param3, param4, param5, param6, param7, param8, param9, param10);
|
||||
|
||||
return trMessage.toString();
|
||||
}
|
||||
|
||||
#include "moc_klocalizedcontext.cpp"
|
||||
#endif
|
||||
@@ -0,0 +1,287 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2011 Marco Martin <mart@kde.org>
|
||||
SPDX-FileCopyrightText: 2015 Aleix Pol Gonzalez <aleixpol@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef KLOCALIZEDCONTEXT_H
|
||||
#define KLOCALIZEDCONTEXT_H
|
||||
|
||||
#include <ki18n_export.h>
|
||||
|
||||
#if KI18N_ENABLE_DEPRECATED_SINCE(6, 8)
|
||||
#include <QObject>
|
||||
#include <QVariant>
|
||||
|
||||
/**
|
||||
* @class KLocalizedContext klocalizedcontext.h <KLocalizedContext>
|
||||
*
|
||||
* This class is meant to be used to simplify integration of the KI18n framework
|
||||
* in QML.
|
||||
*
|
||||
* The way to do so, is by creating this object and setting it as a context
|
||||
* object:
|
||||
*
|
||||
* @code
|
||||
* QQuickView* view = new QQuickView;
|
||||
* view.engine()->rootContext()->setContextObject(new KLocalizedContext(view));
|
||||
* @endcode
|
||||
*
|
||||
* Then i18n*() and xi18n*() functions should be available for use from the code
|
||||
* loaded in the engine, for the view.
|
||||
*
|
||||
* @note Plural functions differ from the C/C++ version. On QML/JS we can get a
|
||||
* real value easily. To solve warnings on those cases we'll cast the first argument
|
||||
* to make sure it's taken into account for the plural.
|
||||
*
|
||||
* @since 5.17
|
||||
* @deprecated since 6.8 Use KLocalizedQmlContext or KLocalization::setupLocalizedContext
|
||||
* instead.
|
||||
*/
|
||||
KI18N_DEPRECATED_VERSION(6, 8, "use KLocalizedQmlContext or KLocalization::setupLocalizedContext() from KF6::I18nQml instead")
|
||||
class KI18N_EXPORT KLocalizedContext : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
/**
|
||||
* This property only needs to be specified if the context is being run on a library.
|
||||
* in an application there is no need to set the translation domain as the application's
|
||||
* domain can be used.
|
||||
*/
|
||||
Q_PROPERTY(QString translationDomain READ translationDomain WRITE setTranslationDomain NOTIFY translationDomainChanged)
|
||||
|
||||
public:
|
||||
explicit KLocalizedContext(QObject *parent = nullptr);
|
||||
~KLocalizedContext() override;
|
||||
|
||||
QString translationDomain() const;
|
||||
void setTranslationDomain(const QString &domain);
|
||||
|
||||
Q_INVOKABLE QString i18n(const QString &message,
|
||||
const QVariant ¶m1 = QVariant(),
|
||||
const QVariant ¶m2 = QVariant(),
|
||||
const QVariant ¶m3 = QVariant(),
|
||||
const QVariant ¶m4 = QVariant(),
|
||||
const QVariant ¶m5 = QVariant(),
|
||||
const QVariant ¶m6 = QVariant(),
|
||||
const QVariant ¶m7 = QVariant(),
|
||||
const QVariant ¶m8 = QVariant(),
|
||||
const QVariant ¶m9 = QVariant(),
|
||||
const QVariant ¶m10 = QVariant()) const;
|
||||
|
||||
Q_INVOKABLE QString i18nc(const QString &context,
|
||||
const QString &message,
|
||||
const QVariant ¶m1 = QVariant(),
|
||||
const QVariant ¶m2 = QVariant(),
|
||||
const QVariant ¶m3 = QVariant(),
|
||||
const QVariant ¶m4 = QVariant(),
|
||||
const QVariant ¶m5 = QVariant(),
|
||||
const QVariant ¶m6 = QVariant(),
|
||||
const QVariant ¶m7 = QVariant(),
|
||||
const QVariant ¶m8 = QVariant(),
|
||||
const QVariant ¶m9 = QVariant(),
|
||||
const QVariant ¶m10 = QVariant()) const;
|
||||
|
||||
Q_INVOKABLE QString i18np(const QString &singular,
|
||||
const QString &plural,
|
||||
const QVariant ¶m1 = QVariant(),
|
||||
const QVariant ¶m2 = QVariant(),
|
||||
const QVariant ¶m3 = QVariant(),
|
||||
const QVariant ¶m4 = QVariant(),
|
||||
const QVariant ¶m5 = QVariant(),
|
||||
const QVariant ¶m6 = QVariant(),
|
||||
const QVariant ¶m7 = QVariant(),
|
||||
const QVariant ¶m8 = QVariant(),
|
||||
const QVariant ¶m9 = QVariant(),
|
||||
const QVariant ¶m10 = QVariant()) const;
|
||||
|
||||
Q_INVOKABLE QString i18ncp(const QString &context,
|
||||
const QString &singular,
|
||||
const QString &plural,
|
||||
const QVariant ¶m1 = QVariant(),
|
||||
const QVariant ¶m2 = QVariant(),
|
||||
const QVariant ¶m3 = QVariant(),
|
||||
const QVariant ¶m4 = QVariant(),
|
||||
const QVariant ¶m5 = QVariant(),
|
||||
const QVariant ¶m6 = QVariant(),
|
||||
const QVariant ¶m7 = QVariant(),
|
||||
const QVariant ¶m8 = QVariant(),
|
||||
const QVariant ¶m9 = QVariant(),
|
||||
const QVariant ¶m10 = QVariant()) const;
|
||||
|
||||
Q_INVOKABLE QString i18nd(const QString &domain,
|
||||
const QString &message,
|
||||
const QVariant ¶m1 = QVariant(),
|
||||
const QVariant ¶m2 = QVariant(),
|
||||
const QVariant ¶m3 = QVariant(),
|
||||
const QVariant ¶m4 = QVariant(),
|
||||
const QVariant ¶m5 = QVariant(),
|
||||
const QVariant ¶m6 = QVariant(),
|
||||
const QVariant ¶m7 = QVariant(),
|
||||
const QVariant ¶m8 = QVariant(),
|
||||
const QVariant ¶m9 = QVariant(),
|
||||
const QVariant ¶m10 = QVariant()) const;
|
||||
|
||||
Q_INVOKABLE QString i18ndc(const QString &domain,
|
||||
const QString &context,
|
||||
const QString &message,
|
||||
const QVariant ¶m1 = QVariant(),
|
||||
const QVariant ¶m2 = QVariant(),
|
||||
const QVariant ¶m3 = QVariant(),
|
||||
const QVariant ¶m4 = QVariant(),
|
||||
const QVariant ¶m5 = QVariant(),
|
||||
const QVariant ¶m6 = QVariant(),
|
||||
const QVariant ¶m7 = QVariant(),
|
||||
const QVariant ¶m8 = QVariant(),
|
||||
const QVariant ¶m9 = QVariant(),
|
||||
const QVariant ¶m10 = QVariant()) const;
|
||||
|
||||
Q_INVOKABLE QString i18ndp(const QString &domain,
|
||||
const QString &singular,
|
||||
const QString &plural,
|
||||
const QVariant ¶m1 = QVariant(),
|
||||
const QVariant ¶m2 = QVariant(),
|
||||
const QVariant ¶m3 = QVariant(),
|
||||
const QVariant ¶m4 = QVariant(),
|
||||
const QVariant ¶m5 = QVariant(),
|
||||
const QVariant ¶m6 = QVariant(),
|
||||
const QVariant ¶m7 = QVariant(),
|
||||
const QVariant ¶m8 = QVariant(),
|
||||
const QVariant ¶m9 = QVariant(),
|
||||
const QVariant ¶m10 = QVariant()) const;
|
||||
|
||||
Q_INVOKABLE QString i18ndcp(const QString &domain,
|
||||
const QString &context,
|
||||
const QString &singular,
|
||||
const QString &plural,
|
||||
const QVariant ¶m1 = QVariant(),
|
||||
const QVariant ¶m2 = QVariant(),
|
||||
const QVariant ¶m3 = QVariant(),
|
||||
const QVariant ¶m4 = QVariant(),
|
||||
const QVariant ¶m5 = QVariant(),
|
||||
const QVariant ¶m6 = QVariant(),
|
||||
const QVariant ¶m7 = QVariant(),
|
||||
const QVariant ¶m8 = QVariant(),
|
||||
const QVariant ¶m9 = QVariant(),
|
||||
const QVariant ¶m10 = QVariant()) const;
|
||||
|
||||
Q_INVOKABLE QString xi18n(const QString &message,
|
||||
const QVariant ¶m1 = QVariant(),
|
||||
const QVariant ¶m2 = QVariant(),
|
||||
const QVariant ¶m3 = QVariant(),
|
||||
const QVariant ¶m4 = QVariant(),
|
||||
const QVariant ¶m5 = QVariant(),
|
||||
const QVariant ¶m6 = QVariant(),
|
||||
const QVariant ¶m7 = QVariant(),
|
||||
const QVariant ¶m8 = QVariant(),
|
||||
const QVariant ¶m9 = QVariant(),
|
||||
const QVariant ¶m10 = QVariant()) const;
|
||||
|
||||
Q_INVOKABLE QString xi18nc(const QString &context,
|
||||
const QString &message,
|
||||
const QVariant ¶m1 = QVariant(),
|
||||
const QVariant ¶m2 = QVariant(),
|
||||
const QVariant ¶m3 = QVariant(),
|
||||
const QVariant ¶m4 = QVariant(),
|
||||
const QVariant ¶m5 = QVariant(),
|
||||
const QVariant ¶m6 = QVariant(),
|
||||
const QVariant ¶m7 = QVariant(),
|
||||
const QVariant ¶m8 = QVariant(),
|
||||
const QVariant ¶m9 = QVariant(),
|
||||
const QVariant ¶m10 = QVariant()) const;
|
||||
|
||||
Q_INVOKABLE QString xi18np(const QString &singular,
|
||||
const QString &plural,
|
||||
const QVariant ¶m1 = QVariant(),
|
||||
const QVariant ¶m2 = QVariant(),
|
||||
const QVariant ¶m3 = QVariant(),
|
||||
const QVariant ¶m4 = QVariant(),
|
||||
const QVariant ¶m5 = QVariant(),
|
||||
const QVariant ¶m6 = QVariant(),
|
||||
const QVariant ¶m7 = QVariant(),
|
||||
const QVariant ¶m8 = QVariant(),
|
||||
const QVariant ¶m9 = QVariant(),
|
||||
const QVariant ¶m10 = QVariant()) const;
|
||||
|
||||
Q_INVOKABLE QString xi18ncp(const QString &context,
|
||||
const QString &singular,
|
||||
const QString &plural,
|
||||
const QVariant ¶m1 = QVariant(),
|
||||
const QVariant ¶m2 = QVariant(),
|
||||
const QVariant ¶m3 = QVariant(),
|
||||
const QVariant ¶m4 = QVariant(),
|
||||
const QVariant ¶m5 = QVariant(),
|
||||
const QVariant ¶m6 = QVariant(),
|
||||
const QVariant ¶m7 = QVariant(),
|
||||
const QVariant ¶m8 = QVariant(),
|
||||
const QVariant ¶m9 = QVariant(),
|
||||
const QVariant ¶m10 = QVariant()) const;
|
||||
|
||||
Q_INVOKABLE QString xi18nd(const QString &domain,
|
||||
const QString &message,
|
||||
const QVariant ¶m1 = QVariant(),
|
||||
const QVariant ¶m2 = QVariant(),
|
||||
const QVariant ¶m3 = QVariant(),
|
||||
const QVariant ¶m4 = QVariant(),
|
||||
const QVariant ¶m5 = QVariant(),
|
||||
const QVariant ¶m6 = QVariant(),
|
||||
const QVariant ¶m7 = QVariant(),
|
||||
const QVariant ¶m8 = QVariant(),
|
||||
const QVariant ¶m9 = QVariant(),
|
||||
const QVariant ¶m10 = QVariant()) const;
|
||||
|
||||
Q_INVOKABLE QString xi18ndc(const QString &domain,
|
||||
const QString &context,
|
||||
const QString &message,
|
||||
const QVariant ¶m1 = QVariant(),
|
||||
const QVariant ¶m2 = QVariant(),
|
||||
const QVariant ¶m3 = QVariant(),
|
||||
const QVariant ¶m4 = QVariant(),
|
||||
const QVariant ¶m5 = QVariant(),
|
||||
const QVariant ¶m6 = QVariant(),
|
||||
const QVariant ¶m7 = QVariant(),
|
||||
const QVariant ¶m8 = QVariant(),
|
||||
const QVariant ¶m9 = QVariant(),
|
||||
const QVariant ¶m10 = QVariant()) const;
|
||||
|
||||
Q_INVOKABLE QString xi18ndp(const QString &domain,
|
||||
const QString &singular,
|
||||
const QString &plural,
|
||||
const QVariant ¶m1 = QVariant(),
|
||||
const QVariant ¶m2 = QVariant(),
|
||||
const QVariant ¶m3 = QVariant(),
|
||||
const QVariant ¶m4 = QVariant(),
|
||||
const QVariant ¶m5 = QVariant(),
|
||||
const QVariant ¶m6 = QVariant(),
|
||||
const QVariant ¶m7 = QVariant(),
|
||||
const QVariant ¶m8 = QVariant(),
|
||||
const QVariant ¶m9 = QVariant(),
|
||||
const QVariant ¶m10 = QVariant()) const;
|
||||
|
||||
Q_INVOKABLE QString xi18ndcp(const QString &domain,
|
||||
const QString &context,
|
||||
const QString &singular,
|
||||
const QString &plural,
|
||||
const QVariant ¶m1 = QVariant(),
|
||||
const QVariant ¶m2 = QVariant(),
|
||||
const QVariant ¶m3 = QVariant(),
|
||||
const QVariant ¶m4 = QVariant(),
|
||||
const QVariant ¶m5 = QVariant(),
|
||||
const QVariant ¶m6 = QVariant(),
|
||||
const QVariant ¶m7 = QVariant(),
|
||||
const QVariant ¶m8 = QVariant(),
|
||||
const QVariant ¶m9 = QVariant(),
|
||||
const QVariant ¶m10 = QVariant()) const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void translationDomainChanged(const QString &translationDomain);
|
||||
|
||||
private:
|
||||
// intentionally not a unique_ptr as this file gets included a lot and using a unique_ptr
|
||||
// results in too many template instantiations
|
||||
class KLocalizedContextPrivate *const d;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "klocalizedtranslator.h"
|
||||
#include "klocalizedstring.h"
|
||||
|
||||
// Qt
|
||||
#include <QMetaObject>
|
||||
#include <QMetaProperty>
|
||||
|
||||
class KLocalizedTranslatorPrivate
|
||||
{
|
||||
public:
|
||||
QString translationDomain;
|
||||
QSet<QString> monitoredContexts;
|
||||
};
|
||||
|
||||
KLocalizedTranslator::KLocalizedTranslator(QObject *parent)
|
||||
: QTranslator(parent)
|
||||
, d(new KLocalizedTranslatorPrivate)
|
||||
{
|
||||
}
|
||||
|
||||
KLocalizedTranslator::~KLocalizedTranslator()
|
||||
{
|
||||
}
|
||||
|
||||
void KLocalizedTranslator::setTranslationDomain(const QString &translationDomain)
|
||||
{
|
||||
d->translationDomain = translationDomain;
|
||||
}
|
||||
|
||||
void KLocalizedTranslator::addContextToMonitor(const QString &context)
|
||||
{
|
||||
d->monitoredContexts.insert(context);
|
||||
}
|
||||
|
||||
void KLocalizedTranslator::removeContextToMonitor(const QString &context)
|
||||
{
|
||||
d->monitoredContexts.remove(context);
|
||||
}
|
||||
|
||||
QString KLocalizedTranslator::translate(const char *context, const char *sourceText, const char *disambiguation, int n) const
|
||||
{
|
||||
if (d->translationDomain.isEmpty() || !d->monitoredContexts.contains(QString::fromUtf8(context))) {
|
||||
return QTranslator::translate(context, sourceText, disambiguation, n);
|
||||
}
|
||||
if (qstrlen(disambiguation) == 0) {
|
||||
return ki18nd(d->translationDomain.toUtf8().constData(), sourceText).toString();
|
||||
} else {
|
||||
return ki18ndc(d->translationDomain.toUtf8().constData(), disambiguation, sourceText).toString();
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_klocalizedtranslator.cpp"
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef KLOCALIZEDTRANSLATOR_H
|
||||
#define KLOCALIZEDTRANSLATOR_H
|
||||
|
||||
#include <ki18n_export.h>
|
||||
|
||||
#include <QTranslator>
|
||||
|
||||
#include <memory>
|
||||
|
||||
class KLocalizedTranslatorPrivate;
|
||||
|
||||
/**
|
||||
* @class KLocalizedTranslator klocalizedtranslator.h <KLocalizedTranslator>
|
||||
*
|
||||
* @brief A QTranslator using KLocalizedString for translations.
|
||||
*
|
||||
* This class allows to translate strings in Qt's translation system with KLocalizedString.
|
||||
* An example is the translation of a dynamically loaded user interface through QUILoader.
|
||||
*
|
||||
* To use this Translator install it in the QCoreApplication and provide the translation domain
|
||||
* to be used. The Translator can operate for multiple contexts, those needs to be specified.
|
||||
*
|
||||
* Example for translating a UI loaded through QUILoader:
|
||||
* @code
|
||||
* // create translator and install in QCoreApplication
|
||||
* KLocalizedTranslator *translator = new KLocalizedTranslator(this);
|
||||
* QCoreApplication::instance()->installTranslator(translator);
|
||||
* translator->setTranslationDomain(QStringLiteral("MyAppsDomain"));
|
||||
*
|
||||
* // create the QUILoader
|
||||
* QUiLoader *loader = new QUiLoader(this);
|
||||
* loader->setLanguageChangeEnabled(true);
|
||||
*
|
||||
* // load the UI
|
||||
* QFile uiFile(QStringLiteral("/path/to/userInterface.ui"));
|
||||
* uiFile.open(QFile::ReadOnly);
|
||||
* QWidget *loadedWidget = loader->load(&uiFile, this);
|
||||
* uiFile.close();
|
||||
*
|
||||
* // the object name of the loaded UI is the context in this case
|
||||
* translator->addContextToMonitor(loadedWidget->objectName());
|
||||
*
|
||||
* // send a LanguageChange event, this will re-translate using our translator
|
||||
* QEvent le(QEvent::LanguageChange);
|
||||
* QCoreApplication::sendEvent(loadedWidget, &le);
|
||||
* @endcode
|
||||
*
|
||||
* @since 5.0
|
||||
**/
|
||||
class KI18N_EXPORT KLocalizedTranslator : public QTranslator
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit KLocalizedTranslator(QObject *parent = nullptr);
|
||||
virtual ~KLocalizedTranslator();
|
||||
QString translate(const char *context, const char *sourceText, const char *disambiguation = nullptr, int n = -1) const override;
|
||||
|
||||
/**
|
||||
* Sets the @p translationDomain to be used.
|
||||
*
|
||||
* The translation domain is required. Without the translation domain any invocation of
|
||||
* translate() will be delegated to the base class.
|
||||
*
|
||||
* @param translationDomain The translation domain to be used.
|
||||
**/
|
||||
void setTranslationDomain(const QString &translationDomain);
|
||||
|
||||
/**
|
||||
* Adds a @p context for which this Translator should be active.
|
||||
*
|
||||
* The Translator only translates texts with a context matching one of the monitored contexts.
|
||||
* If the context is not monitored, the translate() method delegates to the base class.
|
||||
*
|
||||
* @param context The context for which the Translator should be active
|
||||
*
|
||||
* @see removeContextToMonitor
|
||||
**/
|
||||
void addContextToMonitor(const QString &context);
|
||||
|
||||
/**
|
||||
* Stop translating for the given @p context.
|
||||
*
|
||||
* @param context The context for which the Translator should no longer be active
|
||||
*
|
||||
* @see addContextToMonitor
|
||||
**/
|
||||
void removeContextToMonitor(const QString &context);
|
||||
|
||||
private:
|
||||
std::unique_ptr<KLocalizedTranslatorPrivate> const d;
|
||||
};
|
||||
|
||||
#endif // KLOCALIZEDTRANSLATOR_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,83 @@
|
||||
/* This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2007 Chusslove Illich <caslav.ilic@gmx.net>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef KTRANSCRIPT_P_H
|
||||
#define KTRANSCRIPT_P_H
|
||||
|
||||
#include <QHash>
|
||||
#include <QList>
|
||||
#include <QStringList>
|
||||
#include <QVariant>
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* (used by KLocalizedString)
|
||||
*
|
||||
* @c KTranscript provides support for programmable translations.
|
||||
* The class is abstract in order to facilitate dynamic loading.
|
||||
*
|
||||
* @author Chusslove Illich <caslav.ilic@gmx.net>
|
||||
* @short class for supporting programmable translations
|
||||
*/
|
||||
class KTranscript
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Evaluates interpolation.
|
||||
*
|
||||
* @param argv list of interpolation tokens
|
||||
* @param lang language of the translation
|
||||
* @param ctry locale country
|
||||
* @param msgctxt message context
|
||||
* @param dynctxt dynamic context
|
||||
* @param msgid original message
|
||||
* @param subs substitutions for message placeholders
|
||||
* @param vals values that were formatted to substitutions
|
||||
* @param ftrans finalized ordinary translation
|
||||
* @param mods scripting modules to load; the list is cleared after loading
|
||||
* @param error set to the message detailing the problem, if the script
|
||||
failed; set to empty otherwise
|
||||
* @param fallback set to true if the script requested fallback to ordinary
|
||||
translation; set to false otherwise
|
||||
* @return resolved interpolation if evaluation succeeded,
|
||||
* empty string otherwise
|
||||
*/
|
||||
virtual QString eval(const QList<QVariant> &argv,
|
||||
const QString &lang,
|
||||
const QString &ctry,
|
||||
const QString &msgctxt,
|
||||
const QHash<QString, QString> &dynctxt,
|
||||
const QString &msgid,
|
||||
const QStringList &subs,
|
||||
const QList<QVariant> &vals,
|
||||
const QString &ftrans,
|
||||
QList<QStringList> &mods,
|
||||
QString &error,
|
||||
bool &fallback) = 0;
|
||||
|
||||
/**
|
||||
* Returns the list of calls to execute an all messages after the
|
||||
* interpolations are done, as evaluations with no parameters.
|
||||
*
|
||||
* @param lang language of the translation
|
||||
* @return list of post calls
|
||||
*/
|
||||
virtual QStringList postCalls(const QString &lang) = 0;
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~KTranscript()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef KTRANSCRIPT_TESTBUILD
|
||||
KTranscript *autotestCreateKTranscriptImp();
|
||||
void autotestDestroyKTranscriptImp();
|
||||
#endif
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,186 @@
|
||||
/* This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2013 Chusslove Illich <caslav.ilic@gmx.net>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef KUITSETUP_H
|
||||
#define KUITSETUP_H
|
||||
|
||||
#include <ki18n_export.h>
|
||||
|
||||
#include <QHash>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
class KuitSetup;
|
||||
|
||||
/**
|
||||
* Global constants and functions related to KUIT markup.
|
||||
*/
|
||||
namespace Kuit
|
||||
{
|
||||
/**
|
||||
* Visual formats into which KUIT markup can be resolved.
|
||||
*/
|
||||
enum VisualFormat {
|
||||
/**
|
||||
* Visual format not defined.
|
||||
* This value can be explicitly set
|
||||
* (e.g. through \c KLocalizedString::withFormat)
|
||||
* to indicate that the format should be decided
|
||||
* by another mechanism (e.g. context UI marker).
|
||||
*/
|
||||
UndefinedFormat = 0,
|
||||
/**
|
||||
* Plain text.
|
||||
*/
|
||||
PlainText = 10,
|
||||
/**
|
||||
* Qt rich text (HTML subset).
|
||||
*/
|
||||
RichText = 20,
|
||||
/**
|
||||
* Terminal escape sequences.
|
||||
*/
|
||||
TermText = 30,
|
||||
};
|
||||
|
||||
/**
|
||||
* Classification of KUIT tags.
|
||||
*/
|
||||
enum TagClass {
|
||||
/**
|
||||
* Tags wrapping text inserted into running text.
|
||||
*/
|
||||
PhraseTag = 0,
|
||||
/**
|
||||
* Tags splitting text into paragraph-level blocks.
|
||||
*/
|
||||
StructTag = 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* Functions accepted by tag formatting functions.
|
||||
*
|
||||
* \param languages the target languages (by decreasing priority)
|
||||
* \param tagName the wrapping tag name
|
||||
* \param attributes the attribute name-value pairs in the tag
|
||||
* \param text the wrapped text
|
||||
* \param tagPath the ordered list of ancestor tag names, parent first
|
||||
* \param format the target visual format
|
||||
* \return formatted text
|
||||
*/
|
||||
typedef QString (*TagFormatter)(const QStringList &languages,
|
||||
const QString &tagName,
|
||||
const QHash<QString, QString> &attributes,
|
||||
const QString &text,
|
||||
const QStringList &tagPath,
|
||||
Kuit::VisualFormat format);
|
||||
|
||||
/**
|
||||
* Get hold of the KUIT setup object for a given domain.
|
||||
*
|
||||
* \param domain the translation domain
|
||||
* \return pointer to KUIT setup object
|
||||
*/
|
||||
KI18N_EXPORT KuitSetup &setupForDomain(const QByteArray &domain);
|
||||
}
|
||||
|
||||
class KLocalizedString;
|
||||
class KuitSetupPrivate;
|
||||
class KuitFormatterPrivate;
|
||||
|
||||
/**
|
||||
* @class KuitSetup kuitsetup.h <KuitSetup>
|
||||
*
|
||||
* Class for modifying KUIT markup in a given domain.
|
||||
*
|
||||
* Not directly constructed, but obtained through \c Kuit::setupForDomain.
|
||||
*/
|
||||
class KI18N_EXPORT KuitSetup
|
||||
{
|
||||
friend KuitSetup &Kuit::setupForDomain(const QByteArray &domain);
|
||||
friend class KuitFormatterPrivate;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~KuitSetup();
|
||||
|
||||
/**
|
||||
* Set the formatting string for a tag with attributes combination.
|
||||
*
|
||||
* If a new tag name is given, this effectively defines a new tag.
|
||||
* The same holds for attribute names.
|
||||
*
|
||||
* The pattern string \p pattern should contain placeholders
|
||||
* for inserting the text and the attribute values.
|
||||
* %1 will be replaced with the wrapped text, and %2 and upwards
|
||||
* with attribute values in the order given by \p attrNames.
|
||||
* Non markup-aware translation call with context (\c ki18nc)
|
||||
* should be used to create the pattern string.
|
||||
*
|
||||
* In addition to the pattern, a formatting function
|
||||
* of the type \c TagFormatter can be given.
|
||||
* This function receives the full markup parsing context,
|
||||
* so that it can do whatever is necessary with the wrapped text.
|
||||
* The result of this function is then substituted into the pattern.
|
||||
* You can also give an empty pattern (as <tt>KLocalizedString()</tt>)
|
||||
* together with the formatting function, in which case the function
|
||||
* is assumed to do everything and no substitution is performed.
|
||||
*
|
||||
* \param tagName the name of the tag
|
||||
* \param attribNames the names of the attributes (empty names are ignored)
|
||||
* \param format the target visual format
|
||||
* \param pattern the pattern string
|
||||
* \param leadingNewlines the number of new lines (\\n) to be maintained
|
||||
* between any preceding text and the text wrapped
|
||||
* with this tag (for formats where it matters)
|
||||
*/
|
||||
void setTagPattern(const QString &tagName,
|
||||
const QStringList &attribNames,
|
||||
Kuit::VisualFormat format,
|
||||
const KLocalizedString &pattern,
|
||||
Kuit::TagFormatter formatter = nullptr,
|
||||
int leadingNewlines = 0);
|
||||
|
||||
/**
|
||||
* Set the KUIT class of the tag.
|
||||
*
|
||||
* \param tagName the name of the tag
|
||||
* \param aClass the KUIT tag class
|
||||
*/
|
||||
void setTagClass(const QString &tagName, Kuit::TagClass aClass);
|
||||
|
||||
/**
|
||||
* Set the default visual format for a given UI marker.
|
||||
*
|
||||
* Giving <tt>"@<major>"</tt> for \p marker means to set the format
|
||||
* only for standalone <tt>\@\<major\></tt> marker,
|
||||
* while <tt>"@<major>:"</tt> (with trailing colon) means to set
|
||||
* the same format for all <tt>\@\<major\>:\<minor\></tt> combinations.
|
||||
*
|
||||
* Defined UI marker major/minor combinations are listed in the section
|
||||
* \ref uimark_ctxt. If an UI marker combination outside of the defined
|
||||
* is given as \p marker, it will be ignored.
|
||||
*
|
||||
* Setting \c Kuit::UndefinedFormat as \p format
|
||||
* means to fall back to default format for the given UI marker.
|
||||
*
|
||||
* \param marker the UI marker
|
||||
* \param format the visual format
|
||||
*/
|
||||
void setFormatForMarker(const QString &marker, Kuit::VisualFormat format);
|
||||
|
||||
private:
|
||||
KI18N_NO_EXPORT explicit KuitSetup(const QByteArray &domain);
|
||||
Q_DISABLE_COPY(KuitSetup)
|
||||
|
||||
// intentionally not a unique_ptr as this file gets included a lot and using a unique_ptr
|
||||
// results in too many template instantiations
|
||||
KuitSetupPrivate *const d;
|
||||
};
|
||||
|
||||
#endif // KUITSETUP_H
|
||||
@@ -0,0 +1,69 @@
|
||||
/* This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2007, 2013 Chusslove Illich <caslav.ilic@gmx.net>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef KUITSETUP_P_H
|
||||
#define KUITSETUP_P_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
class KuitFormatter;
|
||||
class KuitFormatterPrivate;
|
||||
|
||||
namespace Kuit
|
||||
{
|
||||
/**
|
||||
* Convert &, ", ', <, > characters into XML entities
|
||||
* &, <, >, ', ", respectively.
|
||||
*/
|
||||
QString escape(const QString &text);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* (used by KLocalizedString)
|
||||
*
|
||||
* KuitFormatter resolves KUIT markup in user interface text
|
||||
* into appropriate visual formatting.
|
||||
*
|
||||
* @author Chusslove Illich <caslav.ilic@gmx.net>
|
||||
* @short class for formatting KUIT markup in UI messages
|
||||
*/
|
||||
class KuitFormatter
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param language language to create the formatter for
|
||||
*/
|
||||
KuitFormatter(const QString &language);
|
||||
|
||||
/**
|
||||
* Transforms KUIT markup in the given text into visual formatting.
|
||||
* The appropriate visual formatting is decided based on
|
||||
* the context marker provided in the context string.
|
||||
*
|
||||
* @param domain translation domain from which the text was fetched
|
||||
* @param context context of the text (used if \p format == UndefinedFormat)
|
||||
* @param text text containing the KUIT markup
|
||||
* @param format target visual format
|
||||
* @param isArgument whether this text is inserted into an outer text
|
||||
*/
|
||||
QString format(const QByteArray &domain, const QString &context, const QString &text, Kuit::VisualFormat format) const;
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~KuitFormatter();
|
||||
|
||||
private:
|
||||
KuitFormatter(const KuitFormatter &t);
|
||||
KuitFormatter &operator=(const KuitFormatter &t);
|
||||
|
||||
KuitFormatterPrivate *d;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,124 @@
|
||||
/* This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2015 Lukáš Tinkl <ltinkl@redhat.com>
|
||||
SPDX-FileCopyrightText: 2021,2023 Ingo Klöcker <kloecker@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "ki18n_logging.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QFile>
|
||||
#include <QLibraryInfo>
|
||||
#include <QLocale>
|
||||
#include <QThread>
|
||||
#include <QTranslator>
|
||||
|
||||
#include <memory>
|
||||
|
||||
//
|
||||
// NOTE when changing anything in here, also check whether ECMQmLoader.cpp.in in ECM
|
||||
// needs to be changed as well!
|
||||
//
|
||||
|
||||
using namespace Qt::Literals;
|
||||
|
||||
[[nodiscard]] static QString translationsPath()
|
||||
{
|
||||
#ifndef Q_OS_ANDROID
|
||||
return QLibraryInfo::path(QLibraryInfo::TranslationsPath);
|
||||
#else
|
||||
return u"assets://translations/"_s;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool loadCatalog(QStringView catalog, QStringView language)
|
||||
{
|
||||
Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread());
|
||||
const QString fullPath = translationsPath() + '/'_L1 + catalog + language + ".qm"_L1;
|
||||
if (!QFile::exists(fullPath)) {
|
||||
return false;
|
||||
}
|
||||
auto translator = std::make_unique<QTranslator>(QCoreApplication::instance());
|
||||
if (!translator->load(fullPath)) {
|
||||
qCDebug(KI18N) << "Loading catalog failed:" << fullPath;
|
||||
return false;
|
||||
}
|
||||
QCoreApplication::instance()->installTranslator(translator.release());
|
||||
return true;
|
||||
}
|
||||
|
||||
// load global Qt translation, needed in KDE e.g. by lots of builtin dialogs (QColorDialog, QFontDialog) that we use
|
||||
static bool loadTranslation(QStringView language)
|
||||
{
|
||||
// first, try to load the qt_ meta catalog
|
||||
if (loadCatalog(u"qt_", language)) {
|
||||
return true;
|
||||
}
|
||||
// if loading the meta catalog failed, then try loading the catalogs
|
||||
// it depends on, i.e. qtbase, qtmultimedia separately
|
||||
const auto catalogs = {
|
||||
u"qtbase_",
|
||||
u"qtmultimedia_",
|
||||
};
|
||||
bool success = false;
|
||||
for (const auto &catalog : catalogs) {
|
||||
success |= loadCatalog(catalog, language);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
static QStringList getSystemLanguages()
|
||||
{
|
||||
#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
|
||||
// On Windows and Apple OSs, we cannot use QLocale::system() if an application-specific
|
||||
// language was set by kxmlgui because Qt ignores LANGUAGE on Windows and Apple OSs.
|
||||
// The following code is a simplified variant of QSystemLocale::fallbackUiLocale()
|
||||
// (in qlocale_unix.cpp) ignoring LC_ALL, LC_MESSAGES, and LANG.
|
||||
if (const auto languages = qEnvironmentVariable("LANGUAGE").split(':'_L1, Qt::SkipEmptyParts); !languages.isEmpty()) {
|
||||
return languages;
|
||||
}
|
||||
#endif
|
||||
return QLocale::system().uiLanguages();
|
||||
}
|
||||
|
||||
static void load()
|
||||
{
|
||||
// The way Qt translation system handles plural forms makes it necessary to
|
||||
// have a translation file which contains only plural forms for `en`. That's
|
||||
// why we load the `en` translation unconditionally, then load the
|
||||
// translation for the current locale to overload it.
|
||||
QMetaObject::invokeMethod(QCoreApplication::instance(), [] {
|
||||
loadCatalog(u"qt_", u"en");
|
||||
|
||||
auto languages = getSystemLanguages();
|
||||
for (qsizetype i = 0; i < languages.size(); ++i) {
|
||||
// normalize into the format used in Qt catalog suffixes
|
||||
languages[i].replace('-'_L1, '_'_L1);
|
||||
// make sure we always also have the generic language variant
|
||||
// depending on the platform that might not be in uiLanguages by default
|
||||
// insert that after the last country-specific entry for the same language
|
||||
const auto idx = languages[i].indexOf('_'_L1);
|
||||
if (idx > 0) {
|
||||
const QString genericLang = languages[i].left(idx);
|
||||
qsizetype j = i + 1;
|
||||
for (; j < languages.size(); ++j) {
|
||||
if (!languages[j].startsWith(genericLang)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (languages[j - 1] != genericLang) {
|
||||
languages.insert(j, genericLang);
|
||||
}
|
||||
}
|
||||
}
|
||||
languages.removeDuplicates();
|
||||
for (const auto &language : languages) {
|
||||
if (language == "en"_L1 || loadTranslation(language)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Q_COREAPP_STARTUP_FUNCTION(load)
|
||||
@@ -0,0 +1,15 @@
|
||||
# SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
||||
# SPDX-FileCopyrightText: 2022 Julius Künzel <jk.kdedev@smartlab.uber.space>
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
ecm_add_qml_module(ki18nlocaledataqmlplugin URI "org.kde.i18n.localeData" VERSION 1.0)
|
||||
|
||||
target_sources(ki18nlocaledataqmlplugin PRIVATE
|
||||
ki18nlocaledataqmlplugin.cpp
|
||||
)
|
||||
target_link_libraries(ki18nlocaledataqmlplugin PRIVATE
|
||||
Qt6::Qml
|
||||
KF6::I18nLocaleData
|
||||
)
|
||||
|
||||
ecm_finalize_qml_module(ki18nlocaledataqmlplugin DESTINATION ${KDE_INSTALL_QMLDIR})
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include <KCountry>
|
||||
#include <KCountrySubdivision>
|
||||
#include <KTimeZone>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QQmlContext>
|
||||
#include <QQmlEngine>
|
||||
#include <QQmlExtensionPlugin>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
class KI18nLocaleDataQmlPlugin : public QQmlExtensionPlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
|
||||
public:
|
||||
void registerTypes(const char *uri) override;
|
||||
};
|
||||
|
||||
// return "undefined" for invalid objects, so JS conditionals work as expected
|
||||
template<typename T>
|
||||
static QJSValue toJsValue(T value, QJSEngine *engine)
|
||||
{
|
||||
return value.isValid() ? engine->toScriptValue(value) : QJSValue(QJSValue::UndefinedValue);
|
||||
}
|
||||
|
||||
class KCountryFactory
|
||||
{
|
||||
Q_GADGET
|
||||
Q_PROPERTY(QList<KCountry> allCountries READ allCountries)
|
||||
public:
|
||||
Q_INVOKABLE QJSValue fromAlpha2(const QString &code) const
|
||||
{
|
||||
return toJsValue(KCountry::fromAlpha2(code), m_engine);
|
||||
}
|
||||
Q_INVOKABLE QJSValue fromAlpha3(const QString &code) const
|
||||
{
|
||||
return toJsValue(KCountry::fromAlpha3(code), m_engine);
|
||||
}
|
||||
Q_INVOKABLE QJSValue fromName(const QString &name) const
|
||||
{
|
||||
return toJsValue(KCountry::fromName(name), m_engine);
|
||||
}
|
||||
Q_INVOKABLE QJSValue fromLocation(double latitude, double longitude) const
|
||||
{
|
||||
return toJsValue(KCountry::fromLocation(latitude, longitude), m_engine);
|
||||
}
|
||||
|
||||
QJSEngine *m_engine = nullptr;
|
||||
|
||||
private:
|
||||
QList<KCountry> allCountries() const
|
||||
{
|
||||
return KCountry::allCountries();
|
||||
}
|
||||
};
|
||||
|
||||
class KCountrySubdivisionFactory
|
||||
{
|
||||
Q_GADGET
|
||||
public:
|
||||
Q_INVOKABLE QJSValue fromCode(const QString &code) const
|
||||
{
|
||||
return toJsValue(KCountrySubdivision::fromCode(code), m_engine);
|
||||
}
|
||||
Q_INVOKABLE QJSValue fromLocation(double latitude, double longitude) const
|
||||
{
|
||||
return toJsValue(KCountrySubdivision::fromLocation(latitude, longitude), m_engine);
|
||||
}
|
||||
|
||||
QJSEngine *m_engine = nullptr;
|
||||
};
|
||||
|
||||
class KTimeZoneWrapper
|
||||
{
|
||||
Q_GADGET
|
||||
public:
|
||||
Q_INVOKABLE QJSValue fromLocation(double latitude, double longitude) const
|
||||
{
|
||||
const auto tzId = KTimeZone::fromLocation(latitude, longitude);
|
||||
return tzId ? QString::fromUtf8(tzId) : QJSValue(QJSValue::UndefinedValue);
|
||||
}
|
||||
|
||||
Q_INVOKABLE QJSValue country(const QString &tzId) const
|
||||
{
|
||||
return toJsValue(KTimeZone::country(tzId.toUtf8()), m_engine);
|
||||
}
|
||||
|
||||
QJSEngine *m_engine = nullptr;
|
||||
};
|
||||
|
||||
void KI18nLocaleDataQmlPlugin::registerTypes(const char *uri)
|
||||
{
|
||||
Q_ASSERT(std::strcmp(uri, "org.kde.i18n.localeData") == 0);
|
||||
|
||||
qRegisterMetaType<KCountry>();
|
||||
qRegisterMetaType<KCountrySubdivision>();
|
||||
qRegisterMetaType<QList<KCountrySubdivision>>();
|
||||
|
||||
// HACK qmlplugindump chokes on gadget singletons, to the point of breaking ecm_find_qmlmodule()
|
||||
if (QCoreApplication::applicationName() != QLatin1String("qmlplugindump")) {
|
||||
qmlRegisterSingletonType(uri, 1, 0, "Country", [](QQmlEngine *, QJSEngine *engine) -> QJSValue {
|
||||
KCountryFactory factory;
|
||||
factory.m_engine = engine;
|
||||
return engine->toScriptValue(factory);
|
||||
});
|
||||
qmlRegisterSingletonType(uri, 1, 0, "CountrySubdivision", [](QQmlEngine *, QJSEngine *engine) -> QJSValue {
|
||||
KCountrySubdivisionFactory factory;
|
||||
factory.m_engine = engine;
|
||||
return engine->toScriptValue(factory);
|
||||
});
|
||||
qmlRegisterSingletonType(uri, 1, 0, "TimeZone", [](QQmlEngine *, QJSEngine *engine) -> QJSValue {
|
||||
KTimeZoneWrapper wrapper;
|
||||
wrapper.m_engine = engine;
|
||||
return engine->toScriptValue(wrapper);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#include "ki18nlocaledataqmlplugin.moc"
|
||||
@@ -0,0 +1,91 @@
|
||||
# SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
option(KI18N_EMBEDDED_ISO_CODES_CACHE "Use compiled-in iso-codes data." OFF)
|
||||
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/config-localedata.h.in" "${CMAKE_CURRENT_BINARY_DIR}/config-localedata.h")
|
||||
add_subdirectory(cachegen)
|
||||
|
||||
add_library(KF6I18nLocaleData)
|
||||
add_library(KF6::I18nLocaleData ALIAS KF6I18nLocaleData)
|
||||
|
||||
set_target_properties(KF6I18nLocaleData PROPERTIES
|
||||
VERSION ${KI18N_VERSION}
|
||||
SOVERSION ${KI18N_SOVERSION}
|
||||
EXPORT_NAME I18nLocaleData
|
||||
)
|
||||
|
||||
target_sources(KF6I18nLocaleData PRIVATE
|
||||
isocodes.cpp
|
||||
isocodescache.cpp
|
||||
kcountry.cpp
|
||||
kcountrysubdivision.cpp
|
||||
ktimezone.cpp
|
||||
spatial_index.cpp
|
||||
spatial_index_entry.cpp
|
||||
spatial_index_property.cpp
|
||||
timezonedata.cpp
|
||||
)
|
||||
|
||||
ecm_generate_export_header(KF6I18nLocaleData
|
||||
BASE_NAME KI18nLocaleData
|
||||
GROUP_BASE_NAME KF
|
||||
VERSION ${KF_VERSION}
|
||||
USE_VERSION_HEADER
|
||||
VERSION_BASE_NAME KI18n
|
||||
DEPRECATED_BASE_VERSION 0
|
||||
EXCLUDE_DEPRECATED_BEFORE_AND_AT ${EXCLUDE_DEPRECATED_BEFORE_AND_AT}
|
||||
)
|
||||
|
||||
ecm_qt_declare_logging_category(KF6I18nLocaleData
|
||||
HEADER logging.h
|
||||
IDENTIFIER KI18NLD
|
||||
CATEGORY_NAME kf.i18n.localeData
|
||||
DESCRIPTION "KI18n Locale Data"
|
||||
EXPORT KI18N
|
||||
)
|
||||
|
||||
if (KI18N_EMBEDDED_ISO_CODES_CACHE)
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/iso_3166-1
|
||||
COMMAND ki18n-iso-codes-cachegen --input ${IsoCodes_PREFIX}/share/iso-codes/json/iso_3166-1.json --output ${CMAKE_CURRENT_BINARY_DIR}/iso_3166-1 --code 3166-1
|
||||
DEPENDS ${IsoCodes_PREFIX}/share/iso-codes/json/iso_3166-1.json
|
||||
COMMENT "Generating ISO 3166-1 cache"
|
||||
)
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/iso_3166-2
|
||||
COMMAND ki18n-iso-codes-cachegen --input ${IsoCodes_PREFIX}/share/iso-codes/json/iso_3166-2.json --output ${CMAKE_CURRENT_BINARY_DIR}/iso_3166-2 --code 3166-2
|
||||
DEPENDS ${IsoCodes_PREFIX}/share/iso-codes/json/iso_3166-2.json
|
||||
COMMENT "Generating ISO 3166-2 cache"
|
||||
)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/isocodescache.qrc ${CMAKE_CURRENT_BINARY_DIR}/isocodescache.qrc)
|
||||
target_sources(KF6I18nLocaleData PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/isocodescache.qrc)
|
||||
endif()
|
||||
|
||||
target_include_directories(KF6I18nLocaleData
|
||||
INTERFACE
|
||||
"$<INSTALL_INTERFACE:${KDE_INSTALL_INCLUDEDIR_KF}/KI18nLocaleData>"
|
||||
"$<INSTALL_INTERFACE:${KDE_INSTALL_INCLUDEDIR_KF}/KI18n>" # for version header
|
||||
PUBLIC
|
||||
"$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}>" # for version header
|
||||
)
|
||||
|
||||
target_link_libraries(KF6I18nLocaleData PUBLIC Qt6::Core)
|
||||
target_link_libraries(KF6I18nLocaleData PRIVATE KF6I18n)
|
||||
target_compile_options(KF6I18n PRIVATE -DTRANSLATION_DOMAIN=\"ki18n6\")
|
||||
|
||||
install(TARGETS KF6I18nLocaleData EXPORT KF6I18nTargets ${KF_INSTALL_TARGETS_DEFAULT_ARGS})
|
||||
|
||||
ecm_generate_headers(KI18nLocaleData_HEADERS
|
||||
HEADER_NAMES
|
||||
KCountry
|
||||
KCountrySubdivision
|
||||
KTimeZone
|
||||
REQUIRED_HEADERS KI18nLocaleData_HEADERS
|
||||
)
|
||||
|
||||
install(FILES
|
||||
${KI18nLocaleData_HEADERS}
|
||||
${CMAKE_CURRENT_BINARY_DIR}/ki18nlocaledata_export.h
|
||||
DESTINATION "${KDE_INSTALL_INCLUDEDIR_KF}/KI18nLocaleData" COMPONENT Devel
|
||||
)
|
||||
@@ -0,0 +1,22 @@
|
||||
# SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
if (CMAKE_CROSSCOMPILING)
|
||||
return()
|
||||
endif()
|
||||
|
||||
add_executable(ki18n-iso-codes-cachegen)
|
||||
target_include_directories(ki18n-iso-codes-cachegen PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/..)
|
||||
target_sources(ki18n-iso-codes-cachegen PRIVATE
|
||||
cachegen.cpp
|
||||
../isocodescache.cpp
|
||||
)
|
||||
ecm_qt_declare_logging_category(ki18n-iso-codes-cachegen
|
||||
HEADER logging.h
|
||||
IDENTIFIER KI18NLD
|
||||
CATEGORY_NAME kf.i18n.localeData
|
||||
DESCRIPTION "KI18n Locale Data"
|
||||
)
|
||||
target_link_libraries(ki18n-iso-codes-cachegen PRIVATE
|
||||
Qt6::Core
|
||||
)
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2023 Volker Krause <vkrause@kde.org>
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "../isocodescache_p.h"
|
||||
|
||||
#include <QCommandLineParser>
|
||||
#include <QCoreApplication>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
QCoreApplication app(argc, argv);
|
||||
|
||||
QCommandLineParser parser;
|
||||
QCommandLineOption codeOpt(QStringLiteral("code"), QStringLiteral("ISO code type to generate a cache for [3166-1, 3166-2]"), QStringLiteral("code"));
|
||||
parser.addOption(codeOpt);
|
||||
QCommandLineOption inputOpt(QStringLiteral("input"), QStringLiteral("Input ISO codes JSON file to generate the cache for."), QStringLiteral("input"));
|
||||
parser.addOption(inputOpt);
|
||||
QCommandLineOption outputOpt(QStringLiteral("output"), QStringLiteral("Generated cache file."), QStringLiteral("output"));
|
||||
parser.addOption(outputOpt);
|
||||
parser.addHelpOption();
|
||||
parser.process(app);
|
||||
|
||||
const QString code = parser.value(codeOpt);
|
||||
const QString inputFile = parser.value(inputOpt);
|
||||
const QString outputFile = parser.value(outputOpt);
|
||||
|
||||
if (code == QLatin1String("3166-1")) {
|
||||
IsoCodesCache::createIso3166_1Cache(inputFile, outputFile);
|
||||
} else if (code == QLatin1String("3166-2")) {
|
||||
IsoCodesCache::createIso3166_2Cache(inputFile, outputFile);
|
||||
} else {
|
||||
parser.showHelp();
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef KI18NLOCALEDATA_CONFIG_H
|
||||
#define KI18NLOCALEDATA_CONFIG_H
|
||||
|
||||
#define ISO_CODES_PREFIX "@IsoCodes_PREFIX@"
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: ODbL-1.0
|
||||
* SPDX-FileCopyrightText: OpenStreetMap contributors
|
||||
*
|
||||
* Autogenerated using QGIS - do not edit!
|
||||
*/
|
||||
|
||||
#include "isocodes_p.h"
|
||||
#include "mapentry_p.h"
|
||||
#include "timezone_names_p.h"
|
||||
|
||||
static constexpr const MapEntry<uint16_t> country_timezone_map[] = {
|
||||
{IsoCodes::alpha2CodeToKey("AD"), Tz::Europe_Andorra},
|
||||
{IsoCodes::alpha2CodeToKey("AE"), Tz::Asia_Dubai},
|
||||
{IsoCodes::alpha2CodeToKey("AF"), Tz::Asia_Kabul},
|
||||
{IsoCodes::alpha2CodeToKey("AG"), Tz::America_Antigua},
|
||||
{IsoCodes::alpha2CodeToKey("AI"), Tz::America_Anguilla},
|
||||
{IsoCodes::alpha2CodeToKey("AL"), Tz::Europe_Tirane},
|
||||
{IsoCodes::alpha2CodeToKey("AM"), Tz::Asia_Yerevan},
|
||||
{IsoCodes::alpha2CodeToKey("AO"), Tz::Africa_Luanda},
|
||||
{IsoCodes::alpha2CodeToKey("AR"), Tz::America_Argentina_Buenos_Aires},
|
||||
{IsoCodes::alpha2CodeToKey("AS"), Tz::Pacific_Pago_Pago},
|
||||
{IsoCodes::alpha2CodeToKey("AT"), Tz::Europe_Vienna},
|
||||
{IsoCodes::alpha2CodeToKey("AW"), Tz::America_Aruba},
|
||||
{IsoCodes::alpha2CodeToKey("AX"), Tz::Europe_Helsinki},
|
||||
{IsoCodes::alpha2CodeToKey("AZ"), Tz::Asia_Baku},
|
||||
{IsoCodes::alpha2CodeToKey("BA"), Tz::Europe_Sarajevo},
|
||||
{IsoCodes::alpha2CodeToKey("BB"), Tz::America_Barbados},
|
||||
{IsoCodes::alpha2CodeToKey("BD"), Tz::Asia_Dhaka},
|
||||
{IsoCodes::alpha2CodeToKey("BE"), Tz::Europe_Brussels},
|
||||
{IsoCodes::alpha2CodeToKey("BF"), Tz::Africa_Ouagadougou},
|
||||
{IsoCodes::alpha2CodeToKey("BG"), Tz::Europe_Sofia},
|
||||
{IsoCodes::alpha2CodeToKey("BH"), Tz::Asia_Bahrain},
|
||||
{IsoCodes::alpha2CodeToKey("BI"), Tz::Africa_Bujumbura},
|
||||
{IsoCodes::alpha2CodeToKey("BJ"), Tz::Africa_Porto_Novo},
|
||||
{IsoCodes::alpha2CodeToKey("BL"), Tz::America_St_Barthelemy},
|
||||
{IsoCodes::alpha2CodeToKey("BM"), Tz::Atlantic_Bermuda},
|
||||
{IsoCodes::alpha2CodeToKey("BN"), Tz::Asia_Brunei},
|
||||
{IsoCodes::alpha2CodeToKey("BO"), Tz::America_La_Paz},
|
||||
{IsoCodes::alpha2CodeToKey("BQ"), Tz::America_Kralendijk},
|
||||
{IsoCodes::alpha2CodeToKey("BS"), Tz::America_Nassau},
|
||||
{IsoCodes::alpha2CodeToKey("BT"), Tz::Asia_Thimphu},
|
||||
{IsoCodes::alpha2CodeToKey("BW"), Tz::Africa_Gaborone},
|
||||
{IsoCodes::alpha2CodeToKey("BY"), Tz::Europe_Minsk},
|
||||
{IsoCodes::alpha2CodeToKey("BZ"), Tz::America_Belize},
|
||||
{IsoCodes::alpha2CodeToKey("CC"), Tz::Indian_Cocos},
|
||||
{IsoCodes::alpha2CodeToKey("CF"), Tz::Africa_Bangui},
|
||||
{IsoCodes::alpha2CodeToKey("CG"), Tz::Africa_Brazzaville},
|
||||
{IsoCodes::alpha2CodeToKey("CH"), Tz::Europe_Zurich},
|
||||
{IsoCodes::alpha2CodeToKey("CI"), Tz::Africa_Abidjan},
|
||||
{IsoCodes::alpha2CodeToKey("CK"), Tz::Pacific_Rarotonga},
|
||||
{IsoCodes::alpha2CodeToKey("CM"), Tz::Africa_Douala},
|
||||
{IsoCodes::alpha2CodeToKey("CO"), Tz::America_Bogota},
|
||||
{IsoCodes::alpha2CodeToKey("CR"), Tz::America_Costa_Rica},
|
||||
{IsoCodes::alpha2CodeToKey("CU"), Tz::America_Havana},
|
||||
{IsoCodes::alpha2CodeToKey("CV"), Tz::Atlantic_Cape_Verde},
|
||||
{IsoCodes::alpha2CodeToKey("CW"), Tz::America_Curacao},
|
||||
{IsoCodes::alpha2CodeToKey("CX"), Tz::Indian_Christmas},
|
||||
{IsoCodes::alpha2CodeToKey("CY"), Tz::Asia_Nicosia},
|
||||
{IsoCodes::alpha2CodeToKey("CZ"), Tz::Europe_Prague},
|
||||
{IsoCodes::alpha2CodeToKey("DE"), Tz::Europe_Berlin},
|
||||
{IsoCodes::alpha2CodeToKey("DJ"), Tz::Africa_Djibouti},
|
||||
{IsoCodes::alpha2CodeToKey("DK"), Tz::Europe_Copenhagen},
|
||||
{IsoCodes::alpha2CodeToKey("DM"), Tz::America_Dominica},
|
||||
{IsoCodes::alpha2CodeToKey("DO"), Tz::America_Santo_Domingo},
|
||||
{IsoCodes::alpha2CodeToKey("DZ"), Tz::Africa_Algiers},
|
||||
{IsoCodes::alpha2CodeToKey("EE"), Tz::Europe_Tallinn},
|
||||
{IsoCodes::alpha2CodeToKey("EG"), Tz::Africa_Cairo},
|
||||
{IsoCodes::alpha2CodeToKey("EH"), Tz::Africa_El_Aaiun},
|
||||
{IsoCodes::alpha2CodeToKey("ER"), Tz::Africa_Asmara},
|
||||
{IsoCodes::alpha2CodeToKey("ET"), Tz::Africa_Addis_Ababa},
|
||||
{IsoCodes::alpha2CodeToKey("FI"), Tz::Europe_Helsinki},
|
||||
{IsoCodes::alpha2CodeToKey("FJ"), Tz::Pacific_Fiji},
|
||||
{IsoCodes::alpha2CodeToKey("FK"), Tz::Atlantic_Stanley},
|
||||
{IsoCodes::alpha2CodeToKey("FO"), Tz::Atlantic_Faroe},
|
||||
{IsoCodes::alpha2CodeToKey("GA"), Tz::Africa_Libreville},
|
||||
{IsoCodes::alpha2CodeToKey("GB"), Tz::Europe_London},
|
||||
{IsoCodes::alpha2CodeToKey("GD"), Tz::America_Grenada},
|
||||
{IsoCodes::alpha2CodeToKey("GF"), Tz::America_Cayenne},
|
||||
{IsoCodes::alpha2CodeToKey("GG"), Tz::Europe_Guernsey},
|
||||
{IsoCodes::alpha2CodeToKey("GH"), Tz::Africa_Accra},
|
||||
{IsoCodes::alpha2CodeToKey("GI"), Tz::Europe_Gibraltar},
|
||||
{IsoCodes::alpha2CodeToKey("GM"), Tz::Africa_Banjul},
|
||||
{IsoCodes::alpha2CodeToKey("GN"), Tz::Africa_Conakry},
|
||||
{IsoCodes::alpha2CodeToKey("GP"), Tz::America_Guadeloupe},
|
||||
{IsoCodes::alpha2CodeToKey("GQ"), Tz::Africa_Malabo},
|
||||
{IsoCodes::alpha2CodeToKey("GR"), Tz::Europe_Athens},
|
||||
{IsoCodes::alpha2CodeToKey("GS"), Tz::Atlantic_South_Georgia},
|
||||
{IsoCodes::alpha2CodeToKey("GT"), Tz::America_Guatemala},
|
||||
{IsoCodes::alpha2CodeToKey("GU"), Tz::Pacific_Guam},
|
||||
{IsoCodes::alpha2CodeToKey("GW"), Tz::Africa_Bissau},
|
||||
{IsoCodes::alpha2CodeToKey("GY"), Tz::America_Guyana},
|
||||
{IsoCodes::alpha2CodeToKey("HK"), Tz::Asia_Hong_Kong},
|
||||
{IsoCodes::alpha2CodeToKey("HN"), Tz::America_Tegucigalpa},
|
||||
{IsoCodes::alpha2CodeToKey("HR"), Tz::Europe_Zagreb},
|
||||
{IsoCodes::alpha2CodeToKey("HT"), Tz::America_Port_au_Prince},
|
||||
{IsoCodes::alpha2CodeToKey("HU"), Tz::Europe_Budapest},
|
||||
{IsoCodes::alpha2CodeToKey("IE"), Tz::Europe_Dublin},
|
||||
{IsoCodes::alpha2CodeToKey("IL"), Tz::Asia_Jerusalem},
|
||||
{IsoCodes::alpha2CodeToKey("IM"), Tz::Europe_Isle_of_Man},
|
||||
{IsoCodes::alpha2CodeToKey("IN"), Tz::Asia_Kolkata},
|
||||
{IsoCodes::alpha2CodeToKey("IO"), Tz::Indian_Chagos},
|
||||
{IsoCodes::alpha2CodeToKey("IQ"), Tz::Asia_Baghdad},
|
||||
{IsoCodes::alpha2CodeToKey("IR"), Tz::Asia_Tehran},
|
||||
{IsoCodes::alpha2CodeToKey("IS"), Tz::Atlantic_Reykjavik},
|
||||
{IsoCodes::alpha2CodeToKey("IT"), Tz::Europe_Rome},
|
||||
{IsoCodes::alpha2CodeToKey("JE"), Tz::Europe_Jersey},
|
||||
{IsoCodes::alpha2CodeToKey("JM"), Tz::America_Jamaica},
|
||||
{IsoCodes::alpha2CodeToKey("JO"), Tz::Asia_Amman},
|
||||
{IsoCodes::alpha2CodeToKey("JP"), Tz::Asia_Tokyo},
|
||||
{IsoCodes::alpha2CodeToKey("KE"), Tz::Africa_Nairobi},
|
||||
{IsoCodes::alpha2CodeToKey("KG"), Tz::Asia_Bishkek},
|
||||
{IsoCodes::alpha2CodeToKey("KH"), Tz::Asia_Phnom_Penh},
|
||||
{IsoCodes::alpha2CodeToKey("KM"), Tz::Indian_Comoro},
|
||||
{IsoCodes::alpha2CodeToKey("KN"), Tz::America_St_Kitts},
|
||||
{IsoCodes::alpha2CodeToKey("KP"), Tz::Asia_Pyongyang},
|
||||
{IsoCodes::alpha2CodeToKey("KR"), Tz::Asia_Seoul},
|
||||
{IsoCodes::alpha2CodeToKey("KW"), Tz::Asia_Kuwait},
|
||||
{IsoCodes::alpha2CodeToKey("KY"), Tz::America_Cayman},
|
||||
{IsoCodes::alpha2CodeToKey("LA"), Tz::Asia_Vientiane},
|
||||
{IsoCodes::alpha2CodeToKey("LB"), Tz::Asia_Beirut},
|
||||
{IsoCodes::alpha2CodeToKey("LC"), Tz::America_St_Lucia},
|
||||
{IsoCodes::alpha2CodeToKey("LI"), Tz::Europe_Vaduz},
|
||||
{IsoCodes::alpha2CodeToKey("LK"), Tz::Asia_Colombo},
|
||||
{IsoCodes::alpha2CodeToKey("LR"), Tz::Africa_Monrovia},
|
||||
{IsoCodes::alpha2CodeToKey("LS"), Tz::Africa_Maseru},
|
||||
{IsoCodes::alpha2CodeToKey("LT"), Tz::Europe_Vilnius},
|
||||
{IsoCodes::alpha2CodeToKey("LU"), Tz::Europe_Luxembourg},
|
||||
{IsoCodes::alpha2CodeToKey("LV"), Tz::Europe_Riga},
|
||||
{IsoCodes::alpha2CodeToKey("LY"), Tz::Africa_Tripoli},
|
||||
{IsoCodes::alpha2CodeToKey("MC"), Tz::Europe_Monaco},
|
||||
{IsoCodes::alpha2CodeToKey("MD"), Tz::Europe_Chisinau},
|
||||
{IsoCodes::alpha2CodeToKey("ME"), Tz::Europe_Podgorica},
|
||||
{IsoCodes::alpha2CodeToKey("MF"), Tz::America_Marigot},
|
||||
{IsoCodes::alpha2CodeToKey("MG"), Tz::Indian_Antananarivo},
|
||||
{IsoCodes::alpha2CodeToKey("MK"), Tz::Europe_Skopje},
|
||||
{IsoCodes::alpha2CodeToKey("ML"), Tz::Africa_Bamako},
|
||||
{IsoCodes::alpha2CodeToKey("MM"), Tz::Asia_Yangon},
|
||||
{IsoCodes::alpha2CodeToKey("MO"), Tz::Asia_Macau},
|
||||
{IsoCodes::alpha2CodeToKey("MP"), Tz::Pacific_Saipan},
|
||||
{IsoCodes::alpha2CodeToKey("MQ"), Tz::America_Martinique},
|
||||
{IsoCodes::alpha2CodeToKey("MR"), Tz::Africa_Nouakchott},
|
||||
{IsoCodes::alpha2CodeToKey("MS"), Tz::America_Montserrat},
|
||||
{IsoCodes::alpha2CodeToKey("MT"), Tz::Europe_Malta},
|
||||
{IsoCodes::alpha2CodeToKey("MU"), Tz::Indian_Mauritius},
|
||||
{IsoCodes::alpha2CodeToKey("MV"), Tz::Indian_Maldives},
|
||||
{IsoCodes::alpha2CodeToKey("MW"), Tz::Africa_Blantyre},
|
||||
{IsoCodes::alpha2CodeToKey("MY"), Tz::Asia_Kuala_Lumpur},
|
||||
{IsoCodes::alpha2CodeToKey("MZ"), Tz::Africa_Maputo},
|
||||
{IsoCodes::alpha2CodeToKey("NA"), Tz::Africa_Windhoek},
|
||||
{IsoCodes::alpha2CodeToKey("NC"), Tz::Pacific_Noumea},
|
||||
{IsoCodes::alpha2CodeToKey("NE"), Tz::Africa_Niamey},
|
||||
{IsoCodes::alpha2CodeToKey("NF"), Tz::Pacific_Norfolk},
|
||||
{IsoCodes::alpha2CodeToKey("NG"), Tz::Africa_Lagos},
|
||||
{IsoCodes::alpha2CodeToKey("NI"), Tz::America_Managua},
|
||||
{IsoCodes::alpha2CodeToKey("NO"), Tz::Europe_Oslo},
|
||||
{IsoCodes::alpha2CodeToKey("NP"), Tz::Asia_Kathmandu},
|
||||
{IsoCodes::alpha2CodeToKey("NR"), Tz::Pacific_Nauru},
|
||||
{IsoCodes::alpha2CodeToKey("NU"), Tz::Pacific_Niue},
|
||||
{IsoCodes::alpha2CodeToKey("OM"), Tz::Asia_Muscat},
|
||||
{IsoCodes::alpha2CodeToKey("PA"), Tz::America_Panama},
|
||||
{IsoCodes::alpha2CodeToKey("PE"), Tz::America_Lima},
|
||||
{IsoCodes::alpha2CodeToKey("PH"), Tz::Asia_Manila},
|
||||
{IsoCodes::alpha2CodeToKey("PK"), Tz::Asia_Karachi},
|
||||
{IsoCodes::alpha2CodeToKey("PL"), Tz::Europe_Warsaw},
|
||||
{IsoCodes::alpha2CodeToKey("PM"), Tz::America_Miquelon},
|
||||
{IsoCodes::alpha2CodeToKey("PN"), Tz::Pacific_Pitcairn},
|
||||
{IsoCodes::alpha2CodeToKey("PR"), Tz::America_Puerto_Rico},
|
||||
{IsoCodes::alpha2CodeToKey("PW"), Tz::Pacific_Palau},
|
||||
{IsoCodes::alpha2CodeToKey("PY"), Tz::America_Asuncion},
|
||||
{IsoCodes::alpha2CodeToKey("QA"), Tz::Asia_Qatar},
|
||||
{IsoCodes::alpha2CodeToKey("RE"), Tz::Indian_Reunion},
|
||||
{IsoCodes::alpha2CodeToKey("RO"), Tz::Europe_Bucharest},
|
||||
{IsoCodes::alpha2CodeToKey("RS"), Tz::Europe_Belgrade},
|
||||
{IsoCodes::alpha2CodeToKey("RW"), Tz::Africa_Kigali},
|
||||
{IsoCodes::alpha2CodeToKey("SA"), Tz::Asia_Riyadh},
|
||||
{IsoCodes::alpha2CodeToKey("SB"), Tz::Pacific_Guadalcanal},
|
||||
{IsoCodes::alpha2CodeToKey("SC"), Tz::Indian_Mahe},
|
||||
{IsoCodes::alpha2CodeToKey("SE"), Tz::Europe_Stockholm},
|
||||
{IsoCodes::alpha2CodeToKey("SG"), Tz::Asia_Singapore},
|
||||
{IsoCodes::alpha2CodeToKey("SH"), Tz::Atlantic_St_Helena},
|
||||
{IsoCodes::alpha2CodeToKey("SI"), Tz::Europe_Ljubljana},
|
||||
{IsoCodes::alpha2CodeToKey("SJ"), Tz::Europe_Oslo},
|
||||
{IsoCodes::alpha2CodeToKey("SK"), Tz::Europe_Bratislava},
|
||||
{IsoCodes::alpha2CodeToKey("SL"), Tz::Africa_Freetown},
|
||||
{IsoCodes::alpha2CodeToKey("SM"), Tz::Europe_San_Marino},
|
||||
{IsoCodes::alpha2CodeToKey("SN"), Tz::Africa_Dakar},
|
||||
{IsoCodes::alpha2CodeToKey("SO"), Tz::Africa_Mogadishu},
|
||||
{IsoCodes::alpha2CodeToKey("SR"), Tz::America_Paramaribo},
|
||||
{IsoCodes::alpha2CodeToKey("ST"), Tz::Africa_Sao_Tome},
|
||||
{IsoCodes::alpha2CodeToKey("SV"), Tz::America_El_Salvador},
|
||||
{IsoCodes::alpha2CodeToKey("SX"), Tz::America_Lower_Princes},
|
||||
{IsoCodes::alpha2CodeToKey("SY"), Tz::Asia_Damascus},
|
||||
{IsoCodes::alpha2CodeToKey("SZ"), Tz::Africa_Mbabane},
|
||||
{IsoCodes::alpha2CodeToKey("TC"), Tz::America_Grand_Turk},
|
||||
{IsoCodes::alpha2CodeToKey("TD"), Tz::Africa_Ndjamena},
|
||||
{IsoCodes::alpha2CodeToKey("TF"), Tz::Indian_Kerguelen},
|
||||
{IsoCodes::alpha2CodeToKey("TG"), Tz::Africa_Lome},
|
||||
{IsoCodes::alpha2CodeToKey("TH"), Tz::Asia_Bangkok},
|
||||
{IsoCodes::alpha2CodeToKey("TJ"), Tz::Asia_Dushanbe},
|
||||
{IsoCodes::alpha2CodeToKey("TK"), Tz::Pacific_Fakaofo},
|
||||
{IsoCodes::alpha2CodeToKey("TL"), Tz::Asia_Dili},
|
||||
{IsoCodes::alpha2CodeToKey("TM"), Tz::Asia_Ashgabat},
|
||||
{IsoCodes::alpha2CodeToKey("TN"), Tz::Africa_Tunis},
|
||||
{IsoCodes::alpha2CodeToKey("TO"), Tz::Pacific_Tongatapu},
|
||||
{IsoCodes::alpha2CodeToKey("TR"), Tz::Europe_Istanbul},
|
||||
{IsoCodes::alpha2CodeToKey("TT"), Tz::America_Port_of_Spain},
|
||||
{IsoCodes::alpha2CodeToKey("TV"), Tz::Pacific_Funafuti},
|
||||
{IsoCodes::alpha2CodeToKey("TW"), Tz::Asia_Taipei},
|
||||
{IsoCodes::alpha2CodeToKey("TZ"), Tz::Africa_Dar_es_Salaam},
|
||||
{IsoCodes::alpha2CodeToKey("UG"), Tz::Africa_Kampala},
|
||||
{IsoCodes::alpha2CodeToKey("UY"), Tz::America_Montevideo},
|
||||
{IsoCodes::alpha2CodeToKey("VA"), Tz::Europe_Vatican},
|
||||
{IsoCodes::alpha2CodeToKey("VC"), Tz::America_St_Vincent},
|
||||
{IsoCodes::alpha2CodeToKey("VE"), Tz::America_Caracas},
|
||||
{IsoCodes::alpha2CodeToKey("VG"), Tz::America_Tortola},
|
||||
{IsoCodes::alpha2CodeToKey("VI"), Tz::America_St_Thomas},
|
||||
{IsoCodes::alpha2CodeToKey("VU"), Tz::Pacific_Efate},
|
||||
{IsoCodes::alpha2CodeToKey("WF"), Tz::Pacific_Wallis},
|
||||
{IsoCodes::alpha2CodeToKey("WS"), Tz::Pacific_Apia},
|
||||
{IsoCodes::alpha2CodeToKey("XK"), Tz::Europe_Belgrade},
|
||||
{IsoCodes::alpha2CodeToKey("YE"), Tz::Asia_Aden},
|
||||
{IsoCodes::alpha2CodeToKey("YT"), Tz::Indian_Mayotte},
|
||||
{IsoCodes::alpha2CodeToKey("ZA"), Tz::Africa_Johannesburg},
|
||||
{IsoCodes::alpha2CodeToKey("ZM"), Tz::Africa_Lusaka},
|
||||
{IsoCodes::alpha2CodeToKey("ZW"), Tz::Africa_Harare},
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: CC0-1.0
|
||||
* SPDX-FileCopyrightText: none
|
||||
*
|
||||
* Autogenerated spatial index generated using QGIS.
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
constexpr const float XStart = -180;
|
||||
constexpr const float XRange = 360;
|
||||
constexpr const float YStart = -60;
|
||||
constexpr const float YRange = 140;
|
||||
constexpr const uint8_t ZDepth = 11;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,827 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: ODbL-1.0
|
||||
* SPDX-FileCopyrightText: OpenStreetMap contributors
|
||||
*
|
||||
* Autogenerated using QGIS - do not edit!
|
||||
*/
|
||||
|
||||
#include "isocodes_p.h"
|
||||
#include "mapentry_p.h"
|
||||
#include "timezone_names_p.h"
|
||||
|
||||
static constexpr const MapEntry<uint32_t> subdivision_timezone_map[] = {
|
||||
{IsoCodes::subdivisionCodeToKey("AU-ACT"), Tz::Australia_Sydney},
|
||||
{IsoCodes::subdivisionCodeToKey("AU-NSW"), Tz::Australia_Sydney},
|
||||
{IsoCodes::subdivisionCodeToKey("AU-NSW"), Tz::Australia_Broken_Hill},
|
||||
{IsoCodes::subdivisionCodeToKey("AU-NSW"), Tz::Australia_Lord_Howe},
|
||||
{IsoCodes::subdivisionCodeToKey("AU-NT"), Tz::Australia_Darwin},
|
||||
{IsoCodes::subdivisionCodeToKey("AU-QLD"), Tz::Australia_Brisbane},
|
||||
{IsoCodes::subdivisionCodeToKey("AU-QLD"), Tz::Australia_Lindeman},
|
||||
{IsoCodes::subdivisionCodeToKey("AU-SA"), Tz::Australia_Adelaide},
|
||||
{IsoCodes::subdivisionCodeToKey("AU-TAS"), Tz::Australia_Hobart},
|
||||
{IsoCodes::subdivisionCodeToKey("AU-TAS"), Tz::Australia_Currie},
|
||||
{IsoCodes::subdivisionCodeToKey("AU-TAS"), Tz::Antarctica_Macquarie},
|
||||
{IsoCodes::subdivisionCodeToKey("AU-VIC"), Tz::Australia_Melbourne},
|
||||
{IsoCodes::subdivisionCodeToKey("AU-WA"), Tz::Australia_Perth},
|
||||
{IsoCodes::subdivisionCodeToKey("AU-WA"), Tz::Australia_Eucla},
|
||||
{IsoCodes::subdivisionCodeToKey("BR-AC"), Tz::America_Rio_Branco},
|
||||
{IsoCodes::subdivisionCodeToKey("BR-AL"), Tz::America_Maceio},
|
||||
{IsoCodes::subdivisionCodeToKey("BR-AM"), Tz::America_Manaus},
|
||||
{IsoCodes::subdivisionCodeToKey("BR-AM"), Tz::America_Eirunepe},
|
||||
{IsoCodes::subdivisionCodeToKey("BR-AP"), Tz::America_Belem},
|
||||
{IsoCodes::subdivisionCodeToKey("BR-BA"), Tz::America_Bahia},
|
||||
{IsoCodes::subdivisionCodeToKey("BR-DF"), Tz::America_Sao_Paulo},
|
||||
{IsoCodes::subdivisionCodeToKey("BR-ES"), Tz::America_Sao_Paulo},
|
||||
{IsoCodes::subdivisionCodeToKey("BR-GO"), Tz::America_Sao_Paulo},
|
||||
{IsoCodes::subdivisionCodeToKey("BR-MA"), Tz::America_Fortaleza},
|
||||
{IsoCodes::subdivisionCodeToKey("BR-MG"), Tz::America_Sao_Paulo},
|
||||
{IsoCodes::subdivisionCodeToKey("BR-MS"), Tz::America_Campo_Grande},
|
||||
{IsoCodes::subdivisionCodeToKey("BR-MT"), Tz::America_Cuiaba},
|
||||
{IsoCodes::subdivisionCodeToKey("BR-PA"), Tz::America_Santarem},
|
||||
{IsoCodes::subdivisionCodeToKey("BR-PA"), Tz::America_Belem},
|
||||
{IsoCodes::subdivisionCodeToKey("BR-PB"), Tz::America_Fortaleza},
|
||||
{IsoCodes::subdivisionCodeToKey("BR-PE"), Tz::America_Recife},
|
||||
{IsoCodes::subdivisionCodeToKey("BR-PE"), Tz::America_Noronha},
|
||||
{IsoCodes::subdivisionCodeToKey("BR-PI"), Tz::America_Fortaleza},
|
||||
{IsoCodes::subdivisionCodeToKey("BR-RJ"), Tz::America_Sao_Paulo},
|
||||
// BR-RN
|
||||
{IsoCodes::subdivisionCodeToKey("BR-RO"), Tz::America_Porto_Velho},
|
||||
{IsoCodes::subdivisionCodeToKey("BR-RR"), Tz::America_Boa_Vista},
|
||||
{IsoCodes::subdivisionCodeToKey("BR-RS"), Tz::America_Sao_Paulo},
|
||||
{IsoCodes::subdivisionCodeToKey("BR-SE"), Tz::America_Maceio},
|
||||
{IsoCodes::subdivisionCodeToKey("BR-SP"), Tz::America_Sao_Paulo},
|
||||
{IsoCodes::subdivisionCodeToKey("BR-TO"), Tz::America_Araguaina},
|
||||
{IsoCodes::subdivisionCodeToKey("CA-AB"), Tz::America_Edmonton},
|
||||
{IsoCodes::subdivisionCodeToKey("CA-BC"), Tz::America_Vancouver},
|
||||
{IsoCodes::subdivisionCodeToKey("CA-BC"), Tz::America_Fort_Nelson},
|
||||
{IsoCodes::subdivisionCodeToKey("CA-BC"), Tz::America_Dawson_Creek},
|
||||
{IsoCodes::subdivisionCodeToKey("CA-BC"), Tz::America_Edmonton},
|
||||
{IsoCodes::subdivisionCodeToKey("CA-BC"), Tz::America_Creston},
|
||||
{IsoCodes::subdivisionCodeToKey("CA-MB"), Tz::America_Winnipeg},
|
||||
{IsoCodes::subdivisionCodeToKey("CA-NB"), Tz::America_Moncton},
|
||||
{IsoCodes::subdivisionCodeToKey("CA-NL"), Tz::America_Goose_Bay},
|
||||
{IsoCodes::subdivisionCodeToKey("CA-NL"), Tz::America_St_Johns},
|
||||
{IsoCodes::subdivisionCodeToKey("CA-NS"), Tz::America_Halifax},
|
||||
{IsoCodes::subdivisionCodeToKey("CA-NS"), Tz::America_Glace_Bay},
|
||||
{IsoCodes::subdivisionCodeToKey("CA-NT"), Tz::America_Yellowknife},
|
||||
{IsoCodes::subdivisionCodeToKey("CA-NT"), Tz::America_Inuvik},
|
||||
{IsoCodes::subdivisionCodeToKey("CA-NU"), Tz::America_Iqaluit},
|
||||
{IsoCodes::subdivisionCodeToKey("CA-NU"), Tz::America_Rankin_Inlet},
|
||||
{IsoCodes::subdivisionCodeToKey("CA-NU"), Tz::America_Cambridge_Bay},
|
||||
{IsoCodes::subdivisionCodeToKey("CA-NU"), Tz::America_Pangnirtung},
|
||||
{IsoCodes::subdivisionCodeToKey("CA-NU"), Tz::America_Atikokan},
|
||||
{IsoCodes::subdivisionCodeToKey("CA-NU"), Tz::America_Resolute},
|
||||
{IsoCodes::subdivisionCodeToKey("CA-ON"), Tz::America_Toronto},
|
||||
{IsoCodes::subdivisionCodeToKey("CA-ON"), Tz::America_Rainy_River},
|
||||
{IsoCodes::subdivisionCodeToKey("CA-ON"), Tz::America_Atikokan},
|
||||
{IsoCodes::subdivisionCodeToKey("CA-ON"), Tz::America_Thunder_Bay},
|
||||
{IsoCodes::subdivisionCodeToKey("CA-PE"), Tz::America_Halifax},
|
||||
{IsoCodes::subdivisionCodeToKey("CA-QC"), Tz::America_Toronto},
|
||||
{IsoCodes::subdivisionCodeToKey("CA-QC"), Tz::America_Blanc_Sablon},
|
||||
{IsoCodes::subdivisionCodeToKey("CA-QC"), Tz::America_Halifax},
|
||||
{IsoCodes::subdivisionCodeToKey("CA-SK"), Tz::America_Regina},
|
||||
{IsoCodes::subdivisionCodeToKey("CA-SK"), Tz::America_Swift_Current},
|
||||
{IsoCodes::subdivisionCodeToKey("CA-YT"), Tz::America_Whitehorse},
|
||||
{IsoCodes::subdivisionCodeToKey("CA-YT"), Tz::America_Dawson},
|
||||
{IsoCodes::subdivisionCodeToKey("CD-BC"), Tz::Africa_Kinshasa},
|
||||
{IsoCodes::subdivisionCodeToKey("CD-BU"), Tz::Africa_Lubumbashi},
|
||||
{IsoCodes::subdivisionCodeToKey("CD-EQ"), Tz::Africa_Kinshasa},
|
||||
{IsoCodes::subdivisionCodeToKey("CD-HK"), Tz::Africa_Lubumbashi},
|
||||
{IsoCodes::subdivisionCodeToKey("CD-HL"), Tz::Africa_Lubumbashi},
|
||||
{IsoCodes::subdivisionCodeToKey("CD-HU"), Tz::Africa_Lubumbashi},
|
||||
{IsoCodes::subdivisionCodeToKey("CD-IT"), Tz::Africa_Lubumbashi},
|
||||
{IsoCodes::subdivisionCodeToKey("CD-KC"), Tz::Africa_Lubumbashi},
|
||||
{IsoCodes::subdivisionCodeToKey("CD-KE"), Tz::Africa_Lubumbashi},
|
||||
{IsoCodes::subdivisionCodeToKey("CD-KG"), Tz::Africa_Kinshasa},
|
||||
{IsoCodes::subdivisionCodeToKey("CD-KL"), Tz::Africa_Kinshasa},
|
||||
{IsoCodes::subdivisionCodeToKey("CD-KN"), Tz::Africa_Kinshasa},
|
||||
{IsoCodes::subdivisionCodeToKey("CD-KS"), Tz::Africa_Lubumbashi},
|
||||
{IsoCodes::subdivisionCodeToKey("CD-LO"), Tz::Africa_Lubumbashi},
|
||||
{IsoCodes::subdivisionCodeToKey("CD-LU"), Tz::Africa_Lubumbashi},
|
||||
{IsoCodes::subdivisionCodeToKey("CD-MA"), Tz::Africa_Lubumbashi},
|
||||
{IsoCodes::subdivisionCodeToKey("CD-MN"), Tz::Africa_Kinshasa},
|
||||
{IsoCodes::subdivisionCodeToKey("CD-MO"), Tz::Africa_Kinshasa},
|
||||
{IsoCodes::subdivisionCodeToKey("CD-NK"), Tz::Africa_Lubumbashi},
|
||||
{IsoCodes::subdivisionCodeToKey("CD-NU"), Tz::Africa_Kinshasa},
|
||||
{IsoCodes::subdivisionCodeToKey("CD-SA"), Tz::Africa_Lubumbashi},
|
||||
{IsoCodes::subdivisionCodeToKey("CD-SK"), Tz::Africa_Lubumbashi},
|
||||
{IsoCodes::subdivisionCodeToKey("CD-SU"), Tz::Africa_Kinshasa},
|
||||
{IsoCodes::subdivisionCodeToKey("CD-TA"), Tz::Africa_Lubumbashi},
|
||||
{IsoCodes::subdivisionCodeToKey("CD-TO"), Tz::Africa_Lubumbashi},
|
||||
{IsoCodes::subdivisionCodeToKey("CD-TU"), Tz::Africa_Kinshasa},
|
||||
{IsoCodes::subdivisionCodeToKey("CL-AI"), Tz::America_Santiago},
|
||||
{IsoCodes::subdivisionCodeToKey("CL-AN"), Tz::America_Santiago},
|
||||
{IsoCodes::subdivisionCodeToKey("CL-AP"), Tz::America_Santiago},
|
||||
{IsoCodes::subdivisionCodeToKey("CL-AR"), Tz::America_Santiago},
|
||||
{IsoCodes::subdivisionCodeToKey("CL-AT"), Tz::America_Santiago},
|
||||
{IsoCodes::subdivisionCodeToKey("CL-BI"), Tz::America_Santiago},
|
||||
{IsoCodes::subdivisionCodeToKey("CL-CO"), Tz::America_Santiago},
|
||||
{IsoCodes::subdivisionCodeToKey("CL-LI"), Tz::America_Santiago},
|
||||
{IsoCodes::subdivisionCodeToKey("CL-LL"), Tz::America_Santiago},
|
||||
{IsoCodes::subdivisionCodeToKey("CL-LR"), Tz::America_Santiago},
|
||||
{IsoCodes::subdivisionCodeToKey("CL-MA"), Tz::America_Punta_Arenas},
|
||||
{IsoCodes::subdivisionCodeToKey("CL-ML"), Tz::America_Santiago},
|
||||
{IsoCodes::subdivisionCodeToKey("CL-NB"), Tz::America_Santiago},
|
||||
{IsoCodes::subdivisionCodeToKey("CL-RM"), Tz::America_Santiago},
|
||||
{IsoCodes::subdivisionCodeToKey("CL-TA"), Tz::America_Santiago},
|
||||
{IsoCodes::subdivisionCodeToKey("CL-VS"), Tz::America_Santiago},
|
||||
{IsoCodes::subdivisionCodeToKey("CL-VS"), Tz::Pacific_Easter},
|
||||
{IsoCodes::subdivisionCodeToKey("CN-AH"), Tz::Asia_Shanghai},
|
||||
{IsoCodes::subdivisionCodeToKey("CN-BJ"), Tz::Asia_Shanghai},
|
||||
{IsoCodes::subdivisionCodeToKey("CN-CQ"), Tz::Asia_Shanghai},
|
||||
{IsoCodes::subdivisionCodeToKey("CN-FJ"), Tz::Asia_Shanghai},
|
||||
{IsoCodes::subdivisionCodeToKey("CN-GD"), Tz::Asia_Shanghai},
|
||||
{IsoCodes::subdivisionCodeToKey("CN-GS"), Tz::Asia_Shanghai},
|
||||
{IsoCodes::subdivisionCodeToKey("CN-GX"), Tz::Asia_Shanghai},
|
||||
{IsoCodes::subdivisionCodeToKey("CN-GZ"), Tz::Asia_Shanghai},
|
||||
{IsoCodes::subdivisionCodeToKey("CN-HA"), Tz::Asia_Shanghai},
|
||||
{IsoCodes::subdivisionCodeToKey("CN-HB"), Tz::Asia_Shanghai},
|
||||
{IsoCodes::subdivisionCodeToKey("CN-HE"), Tz::Asia_Shanghai},
|
||||
{IsoCodes::subdivisionCodeToKey("CN-HI"), Tz::Asia_Shanghai},
|
||||
{IsoCodes::subdivisionCodeToKey("CN-HK"), Tz::Asia_Hong_Kong},
|
||||
{IsoCodes::subdivisionCodeToKey("CN-HL"), Tz::Asia_Shanghai},
|
||||
{IsoCodes::subdivisionCodeToKey("CN-HN"), Tz::Asia_Shanghai},
|
||||
{IsoCodes::subdivisionCodeToKey("CN-JL"), Tz::Asia_Shanghai},
|
||||
{IsoCodes::subdivisionCodeToKey("CN-JS"), Tz::Asia_Shanghai},
|
||||
{IsoCodes::subdivisionCodeToKey("CN-JX"), Tz::Asia_Shanghai},
|
||||
{IsoCodes::subdivisionCodeToKey("CN-LN"), Tz::Asia_Shanghai},
|
||||
{IsoCodes::subdivisionCodeToKey("CN-MO"), Tz::Asia_Macau},
|
||||
{IsoCodes::subdivisionCodeToKey("CN-NM"), Tz::Asia_Shanghai},
|
||||
{IsoCodes::subdivisionCodeToKey("CN-NX"), Tz::Asia_Shanghai},
|
||||
{IsoCodes::subdivisionCodeToKey("CN-QH"), Tz::Asia_Shanghai},
|
||||
{IsoCodes::subdivisionCodeToKey("CN-SC"), Tz::Asia_Shanghai},
|
||||
{IsoCodes::subdivisionCodeToKey("CN-SD"), Tz::Asia_Shanghai},
|
||||
{IsoCodes::subdivisionCodeToKey("CN-SH"), Tz::Asia_Shanghai},
|
||||
{IsoCodes::subdivisionCodeToKey("CN-SN"), Tz::Asia_Shanghai},
|
||||
{IsoCodes::subdivisionCodeToKey("CN-SX"), Tz::Asia_Shanghai},
|
||||
{IsoCodes::subdivisionCodeToKey("CN-TJ"), Tz::Asia_Shanghai},
|
||||
{IsoCodes::subdivisionCodeToKey("CN-XJ"), Tz::Asia_Shanghai},
|
||||
{IsoCodes::subdivisionCodeToKey("CN-XJ"), Tz::Asia_Urumqi},
|
||||
{IsoCodes::subdivisionCodeToKey("CN-XZ"), Tz::Asia_Shanghai},
|
||||
{IsoCodes::subdivisionCodeToKey("CN-XZ"), Tz::Asia_Thimphu},
|
||||
{IsoCodes::subdivisionCodeToKey("CN-YN"), Tz::Asia_Shanghai},
|
||||
{IsoCodes::subdivisionCodeToKey("CN-ZJ"), Tz::Asia_Shanghai},
|
||||
{IsoCodes::subdivisionCodeToKey("EC-A"), Tz::America_Guayaquil},
|
||||
{IsoCodes::subdivisionCodeToKey("EC-B"), Tz::America_Guayaquil},
|
||||
{IsoCodes::subdivisionCodeToKey("EC-C"), Tz::America_Guayaquil},
|
||||
{IsoCodes::subdivisionCodeToKey("EC-D"), Tz::America_Guayaquil},
|
||||
{IsoCodes::subdivisionCodeToKey("EC-E"), Tz::America_Guayaquil},
|
||||
{IsoCodes::subdivisionCodeToKey("EC-F"), Tz::America_Guayaquil},
|
||||
{IsoCodes::subdivisionCodeToKey("EC-G"), Tz::America_Guayaquil},
|
||||
{IsoCodes::subdivisionCodeToKey("EC-H"), Tz::America_Guayaquil},
|
||||
{IsoCodes::subdivisionCodeToKey("EC-I"), Tz::America_Guayaquil},
|
||||
{IsoCodes::subdivisionCodeToKey("EC-L"), Tz::America_Guayaquil},
|
||||
{IsoCodes::subdivisionCodeToKey("EC-M"), Tz::America_Guayaquil},
|
||||
{IsoCodes::subdivisionCodeToKey("EC-N"), Tz::America_Guayaquil},
|
||||
{IsoCodes::subdivisionCodeToKey("EC-O"), Tz::America_Guayaquil},
|
||||
{IsoCodes::subdivisionCodeToKey("EC-P"), Tz::America_Guayaquil},
|
||||
{IsoCodes::subdivisionCodeToKey("EC-R"), Tz::America_Guayaquil},
|
||||
{IsoCodes::subdivisionCodeToKey("EC-S"), Tz::America_Guayaquil},
|
||||
{IsoCodes::subdivisionCodeToKey("EC-SD"), Tz::America_Guayaquil},
|
||||
{IsoCodes::subdivisionCodeToKey("EC-SE"), Tz::America_Guayaquil},
|
||||
{IsoCodes::subdivisionCodeToKey("EC-T"), Tz::America_Guayaquil},
|
||||
{IsoCodes::subdivisionCodeToKey("EC-U"), Tz::America_Guayaquil},
|
||||
{IsoCodes::subdivisionCodeToKey("EC-W"), Tz::Pacific_Galapagos},
|
||||
{IsoCodes::subdivisionCodeToKey("EC-X"), Tz::America_Guayaquil},
|
||||
{IsoCodes::subdivisionCodeToKey("EC-Y"), Tz::America_Guayaquil},
|
||||
{IsoCodes::subdivisionCodeToKey("EC-Z"), Tz::America_Guayaquil},
|
||||
{IsoCodes::subdivisionCodeToKey("ES-AN"), Tz::Europe_Madrid},
|
||||
{IsoCodes::subdivisionCodeToKey("ES-AR"), Tz::Europe_Madrid},
|
||||
{IsoCodes::subdivisionCodeToKey("ES-AS"), Tz::Europe_Madrid},
|
||||
{IsoCodes::subdivisionCodeToKey("ES-CB"), Tz::Europe_Madrid},
|
||||
{IsoCodes::subdivisionCodeToKey("ES-CE"), Tz::Africa_Ceuta},
|
||||
{IsoCodes::subdivisionCodeToKey("ES-CL"), Tz::Europe_Madrid},
|
||||
{IsoCodes::subdivisionCodeToKey("ES-CM"), Tz::Europe_Madrid},
|
||||
{IsoCodes::subdivisionCodeToKey("ES-CN"), Tz::Atlantic_Canary},
|
||||
{IsoCodes::subdivisionCodeToKey("ES-CT"), Tz::Europe_Madrid},
|
||||
{IsoCodes::subdivisionCodeToKey("ES-EX"), Tz::Europe_Madrid},
|
||||
{IsoCodes::subdivisionCodeToKey("ES-GA"), Tz::Europe_Madrid},
|
||||
{IsoCodes::subdivisionCodeToKey("ES-IB"), Tz::Europe_Madrid},
|
||||
{IsoCodes::subdivisionCodeToKey("ES-MC"), Tz::Europe_Madrid},
|
||||
{IsoCodes::subdivisionCodeToKey("ES-MD"), Tz::Europe_Madrid},
|
||||
{IsoCodes::subdivisionCodeToKey("ES-ML"), Tz::Africa_Ceuta},
|
||||
{IsoCodes::subdivisionCodeToKey("ES-NC"), Tz::Europe_Madrid},
|
||||
{IsoCodes::subdivisionCodeToKey("ES-PV"), Tz::Europe_Madrid},
|
||||
{IsoCodes::subdivisionCodeToKey("ES-RI"), Tz::Europe_Madrid},
|
||||
{IsoCodes::subdivisionCodeToKey("ES-VC"), Tz::Europe_Madrid},
|
||||
{IsoCodes::subdivisionCodeToKey("FM-KSA"), Tz::Pacific_Kosrae},
|
||||
{IsoCodes::subdivisionCodeToKey("FM-PNI"), Tz::Pacific_Pohnpei},
|
||||
{IsoCodes::subdivisionCodeToKey("FM-TRK"), Tz::Pacific_Chuuk},
|
||||
{IsoCodes::subdivisionCodeToKey("FM-YAP"), Tz::Pacific_Chuuk},
|
||||
{IsoCodes::subdivisionCodeToKey("FR-ARA"), Tz::Europe_Paris},
|
||||
{IsoCodes::subdivisionCodeToKey("FR-BFC"), Tz::Europe_Paris},
|
||||
{IsoCodes::subdivisionCodeToKey("FR-BL"), Tz::America_St_Barthelemy},
|
||||
{IsoCodes::subdivisionCodeToKey("FR-BRE"), Tz::Europe_Paris},
|
||||
{IsoCodes::subdivisionCodeToKey("FR-COR"), Tz::Europe_Paris},
|
||||
// FR-CP
|
||||
{IsoCodes::subdivisionCodeToKey("FR-CVL"), Tz::Europe_Paris},
|
||||
{IsoCodes::subdivisionCodeToKey("FR-GES"), Tz::Europe_Paris},
|
||||
{IsoCodes::subdivisionCodeToKey("FR-GF"), Tz::America_Cayenne},
|
||||
{IsoCodes::subdivisionCodeToKey("FR-GUA"), Tz::America_Guadeloupe},
|
||||
{IsoCodes::subdivisionCodeToKey("FR-HDF"), Tz::Europe_Paris},
|
||||
{IsoCodes::subdivisionCodeToKey("FR-IDF"), Tz::Europe_Paris},
|
||||
{IsoCodes::subdivisionCodeToKey("FR-LRE"), Tz::Indian_Reunion},
|
||||
{IsoCodes::subdivisionCodeToKey("FR-MAY"), Tz::Indian_Mayotte},
|
||||
{IsoCodes::subdivisionCodeToKey("FR-MF"), Tz::America_Marigot},
|
||||
{IsoCodes::subdivisionCodeToKey("FR-MQ"), Tz::America_Martinique},
|
||||
{IsoCodes::subdivisionCodeToKey("FR-NAQ"), Tz::Europe_Paris},
|
||||
{IsoCodes::subdivisionCodeToKey("FR-NC"), Tz::Pacific_Noumea},
|
||||
{IsoCodes::subdivisionCodeToKey("FR-NOR"), Tz::Europe_Paris},
|
||||
{IsoCodes::subdivisionCodeToKey("FR-OCC"), Tz::Europe_Paris},
|
||||
{IsoCodes::subdivisionCodeToKey("FR-PAC"), Tz::Europe_Paris},
|
||||
{IsoCodes::subdivisionCodeToKey("FR-PDL"), Tz::Europe_Paris},
|
||||
{IsoCodes::subdivisionCodeToKey("FR-PF"), Tz::Pacific_Tahiti},
|
||||
{IsoCodes::subdivisionCodeToKey("FR-PF"), Tz::Pacific_Marquesas},
|
||||
{IsoCodes::subdivisionCodeToKey("FR-PF"), Tz::Pacific_Gambier},
|
||||
{IsoCodes::subdivisionCodeToKey("FR-PM"), Tz::America_Miquelon},
|
||||
{IsoCodes::subdivisionCodeToKey("FR-TF"), Tz::Indian_Kerguelen},
|
||||
{IsoCodes::subdivisionCodeToKey("FR-WF"), Tz::Pacific_Wallis},
|
||||
{IsoCodes::subdivisionCodeToKey("GE-AB"), Tz::Asia_Tbilisi},
|
||||
{IsoCodes::subdivisionCodeToKey("GE-AB"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("GE-AJ"), Tz::Asia_Tbilisi},
|
||||
{IsoCodes::subdivisionCodeToKey("GE-GU"), Tz::Asia_Tbilisi},
|
||||
{IsoCodes::subdivisionCodeToKey("GE-IM"), Tz::Asia_Tbilisi},
|
||||
{IsoCodes::subdivisionCodeToKey("GE-KA"), Tz::Asia_Tbilisi},
|
||||
{IsoCodes::subdivisionCodeToKey("GE-KK"), Tz::Asia_Tbilisi},
|
||||
{IsoCodes::subdivisionCodeToKey("GE-MM"), Tz::Asia_Tbilisi},
|
||||
{IsoCodes::subdivisionCodeToKey("GE-RL"), Tz::Asia_Tbilisi},
|
||||
{IsoCodes::subdivisionCodeToKey("GE-SJ"), Tz::Asia_Tbilisi},
|
||||
{IsoCodes::subdivisionCodeToKey("GE-SK"), Tz::Asia_Tbilisi},
|
||||
{IsoCodes::subdivisionCodeToKey("GE-SZ"), Tz::Asia_Tbilisi},
|
||||
{IsoCodes::subdivisionCodeToKey("GE-TB"), Tz::Asia_Tbilisi},
|
||||
{IsoCodes::subdivisionCodeToKey("GL-AV"), Tz::America_Nuuk},
|
||||
{IsoCodes::subdivisionCodeToKey("GL-AV"), Tz::America_Thule},
|
||||
{IsoCodes::subdivisionCodeToKey("GL-KU"), Tz::America_Nuuk},
|
||||
{IsoCodes::subdivisionCodeToKey("GL-QE"), Tz::America_Nuuk},
|
||||
{IsoCodes::subdivisionCodeToKey("GL-QT"), Tz::America_Nuuk},
|
||||
{IsoCodes::subdivisionCodeToKey("GL-SM"), Tz::America_Nuuk},
|
||||
{IsoCodes::subdivisionCodeToKey("GL-SM"), Tz::America_Scoresbysund},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-AC"), Tz::Asia_Jakarta},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-BA"), Tz::Asia_Makassar},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-BB"), Tz::Asia_Jakarta},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-BE"), Tz::Asia_Jakarta},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-BT"), Tz::Asia_Jakarta},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-GO"), Tz::Asia_Makassar},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-JA"), Tz::Asia_Jakarta},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-JB"), Tz::Asia_Jakarta},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-JI"), Tz::Asia_Jakarta},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-JK"), Tz::Asia_Jakarta},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-JT"), Tz::Asia_Jakarta},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-JW"), Tz::Asia_Jakarta},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-KA"), Tz::Asia_Pontianak},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-KA"), Tz::Asia_Makassar},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-KB"), Tz::Asia_Pontianak},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-KI"), Tz::Asia_Makassar},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-KR"), Tz::Asia_Jakarta},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-KS"), Tz::Asia_Makassar},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-KT"), Tz::Asia_Pontianak},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-KU"), Tz::Asia_Makassar},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-LA"), Tz::Asia_Jakarta},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-MA"), Tz::Asia_Jayapura},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-ML"), Tz::Asia_Jayapura},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-MU"), Tz::Asia_Jayapura},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-NB"), Tz::Asia_Makassar},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-NT"), Tz::Asia_Makassar},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-NT"), Tz::Asia_Dili},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-NU"), Tz::Asia_Makassar},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-NU"), Tz::Asia_Dili},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-PA"), Tz::Asia_Jayapura},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-PB"), Tz::Asia_Jayapura},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-PP"), Tz::Asia_Jayapura},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-RI"), Tz::Asia_Jakarta},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-SA"), Tz::Asia_Makassar},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-SB"), Tz::Asia_Jakarta},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-SG"), Tz::Asia_Makassar},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-SL"), Tz::Asia_Makassar},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-SM"), Tz::Asia_Jakarta},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-SN"), Tz::Asia_Makassar},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-SR"), Tz::Asia_Makassar},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-SS"), Tz::Asia_Jakarta},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-ST"), Tz::Asia_Makassar},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-SU"), Tz::Asia_Jakarta},
|
||||
{IsoCodes::subdivisionCodeToKey("ID-YO"), Tz::Asia_Jakarta},
|
||||
{IsoCodes::subdivisionCodeToKey("KI-G"), Tz::Pacific_Tarawa},
|
||||
{IsoCodes::subdivisionCodeToKey("KI-L"), Tz::Pacific_Kiritimati},
|
||||
{IsoCodes::subdivisionCodeToKey("KI-P"), Tz::Pacific_Enderbury},
|
||||
{IsoCodes::subdivisionCodeToKey("KZ-AKM"), Tz::Asia_Almaty},
|
||||
{IsoCodes::subdivisionCodeToKey("KZ-AKT"), Tz::Asia_Aqtobe},
|
||||
{IsoCodes::subdivisionCodeToKey("KZ-ALA"), Tz::Asia_Almaty},
|
||||
{IsoCodes::subdivisionCodeToKey("KZ-ALM"), Tz::Asia_Almaty},
|
||||
{IsoCodes::subdivisionCodeToKey("KZ-AST"), Tz::Asia_Almaty},
|
||||
{IsoCodes::subdivisionCodeToKey("KZ-ATY"), Tz::Asia_Atyrau},
|
||||
{IsoCodes::subdivisionCodeToKey("KZ-BAY"), Tz::Asia_Qyzylorda},
|
||||
{IsoCodes::subdivisionCodeToKey("KZ-KAR"), Tz::Asia_Almaty},
|
||||
{IsoCodes::subdivisionCodeToKey("KZ-KUS"), Tz::Asia_Qostanay},
|
||||
{IsoCodes::subdivisionCodeToKey("KZ-KZY"), Tz::Asia_Qyzylorda},
|
||||
{IsoCodes::subdivisionCodeToKey("KZ-MAN"), Tz::Asia_Aqtau},
|
||||
{IsoCodes::subdivisionCodeToKey("KZ-PAV"), Tz::Asia_Almaty},
|
||||
{IsoCodes::subdivisionCodeToKey("KZ-SEV"), Tz::Asia_Almaty},
|
||||
{IsoCodes::subdivisionCodeToKey("KZ-SHY"), Tz::Asia_Almaty},
|
||||
{IsoCodes::subdivisionCodeToKey("KZ-VOS"), Tz::Asia_Almaty},
|
||||
{IsoCodes::subdivisionCodeToKey("KZ-YUZ"), Tz::Asia_Almaty},
|
||||
{IsoCodes::subdivisionCodeToKey("KZ-ZAP"), Tz::Asia_Oral},
|
||||
{IsoCodes::subdivisionCodeToKey("KZ-ZHA"), Tz::Asia_Almaty},
|
||||
{IsoCodes::subdivisionCodeToKey("MA-01"), Tz::Africa_Casablanca},
|
||||
{IsoCodes::subdivisionCodeToKey("MA-02"), Tz::Africa_Casablanca},
|
||||
{IsoCodes::subdivisionCodeToKey("MA-03"), Tz::Africa_Casablanca},
|
||||
{IsoCodes::subdivisionCodeToKey("MA-04"), Tz::Africa_Casablanca},
|
||||
{IsoCodes::subdivisionCodeToKey("MA-05"), Tz::Africa_Casablanca},
|
||||
{IsoCodes::subdivisionCodeToKey("MA-06"), Tz::Africa_Casablanca},
|
||||
{IsoCodes::subdivisionCodeToKey("MA-07"), Tz::Africa_Casablanca},
|
||||
{IsoCodes::subdivisionCodeToKey("MA-08"), Tz::Africa_Casablanca},
|
||||
{IsoCodes::subdivisionCodeToKey("MA-09"), Tz::Africa_Casablanca},
|
||||
{IsoCodes::subdivisionCodeToKey("MA-10"), Tz::Africa_Casablanca},
|
||||
{IsoCodes::subdivisionCodeToKey("MA-10"), Tz::Africa_El_Aaiun},
|
||||
{IsoCodes::subdivisionCodeToKey("MA-11"), Tz::Africa_El_Aaiun},
|
||||
{IsoCodes::subdivisionCodeToKey("MA-11"), Tz::Africa_Casablanca},
|
||||
{IsoCodes::subdivisionCodeToKey("MA-12"), Tz::Africa_El_Aaiun},
|
||||
{IsoCodes::subdivisionCodeToKey("MH-L"), Tz::Pacific_Majuro},
|
||||
{IsoCodes::subdivisionCodeToKey("MH-L"), Tz::Pacific_Kwajalein},
|
||||
{IsoCodes::subdivisionCodeToKey("MH-T"), Tz::Pacific_Majuro},
|
||||
{IsoCodes::subdivisionCodeToKey("MN-035"), Tz::Asia_Ulaanbaatar},
|
||||
{IsoCodes::subdivisionCodeToKey("MN-037"), Tz::Asia_Ulaanbaatar},
|
||||
{IsoCodes::subdivisionCodeToKey("MN-039"), Tz::Asia_Ulaanbaatar},
|
||||
{IsoCodes::subdivisionCodeToKey("MN-041"), Tz::Asia_Ulaanbaatar},
|
||||
{IsoCodes::subdivisionCodeToKey("MN-043"), Tz::Asia_Hovd},
|
||||
{IsoCodes::subdivisionCodeToKey("MN-046"), Tz::Asia_Hovd},
|
||||
{IsoCodes::subdivisionCodeToKey("MN-047"), Tz::Asia_Ulaanbaatar},
|
||||
{IsoCodes::subdivisionCodeToKey("MN-049"), Tz::Asia_Ulaanbaatar},
|
||||
{IsoCodes::subdivisionCodeToKey("MN-051"), Tz::Asia_Choibalsan},
|
||||
{IsoCodes::subdivisionCodeToKey("MN-053"), Tz::Asia_Ulaanbaatar},
|
||||
{IsoCodes::subdivisionCodeToKey("MN-055"), Tz::Asia_Ulaanbaatar},
|
||||
{IsoCodes::subdivisionCodeToKey("MN-057"), Tz::Asia_Hovd},
|
||||
{IsoCodes::subdivisionCodeToKey("MN-059"), Tz::Asia_Ulaanbaatar},
|
||||
{IsoCodes::subdivisionCodeToKey("MN-061"), Tz::Asia_Choibalsan},
|
||||
{IsoCodes::subdivisionCodeToKey("MN-063"), Tz::Asia_Ulaanbaatar},
|
||||
{IsoCodes::subdivisionCodeToKey("MN-064"), Tz::Asia_Ulaanbaatar},
|
||||
{IsoCodes::subdivisionCodeToKey("MN-065"), Tz::Asia_Hovd},
|
||||
{IsoCodes::subdivisionCodeToKey("MN-067"), Tz::Asia_Ulaanbaatar},
|
||||
{IsoCodes::subdivisionCodeToKey("MN-069"), Tz::Asia_Ulaanbaatar},
|
||||
{IsoCodes::subdivisionCodeToKey("MN-071"), Tz::Asia_Hovd},
|
||||
{IsoCodes::subdivisionCodeToKey("MN-073"), Tz::Asia_Ulaanbaatar},
|
||||
{IsoCodes::subdivisionCodeToKey("MN-1"), Tz::Asia_Ulaanbaatar},
|
||||
{IsoCodes::subdivisionCodeToKey("MX-AGU"), Tz::America_Mexico_City},
|
||||
{IsoCodes::subdivisionCodeToKey("MX-BCN"), Tz::America_Tijuana},
|
||||
{IsoCodes::subdivisionCodeToKey("MX-BCS"), Tz::America_Mazatlan},
|
||||
{IsoCodes::subdivisionCodeToKey("MX-CAM"), Tz::America_Merida},
|
||||
{IsoCodes::subdivisionCodeToKey("MX-CHH"), Tz::America_Chihuahua},
|
||||
{IsoCodes::subdivisionCodeToKey("MX-CHH"), Tz::America_Ojinaga},
|
||||
{IsoCodes::subdivisionCodeToKey("MX-CHP"), Tz::America_Mexico_City},
|
||||
{IsoCodes::subdivisionCodeToKey("MX-CMX"), Tz::America_Mexico_City},
|
||||
{IsoCodes::subdivisionCodeToKey("MX-COA"), Tz::America_Monterrey},
|
||||
{IsoCodes::subdivisionCodeToKey("MX-COA"), Tz::America_Matamoros},
|
||||
{IsoCodes::subdivisionCodeToKey("MX-COL"), Tz::America_Mexico_City},
|
||||
{IsoCodes::subdivisionCodeToKey("MX-DUR"), Tz::America_Monterrey},
|
||||
{IsoCodes::subdivisionCodeToKey("MX-GRO"), Tz::America_Mexico_City},
|
||||
{IsoCodes::subdivisionCodeToKey("MX-GUA"), Tz::America_Mexico_City},
|
||||
{IsoCodes::subdivisionCodeToKey("MX-HID"), Tz::America_Mexico_City},
|
||||
{IsoCodes::subdivisionCodeToKey("MX-JAL"), Tz::America_Mexico_City},
|
||||
{IsoCodes::subdivisionCodeToKey("MX-MEX"), Tz::America_Mexico_City},
|
||||
{IsoCodes::subdivisionCodeToKey("MX-MIC"), Tz::America_Mexico_City},
|
||||
{IsoCodes::subdivisionCodeToKey("MX-MOR"), Tz::America_Mexico_City},
|
||||
{IsoCodes::subdivisionCodeToKey("MX-NAY"), Tz::America_Mazatlan},
|
||||
{IsoCodes::subdivisionCodeToKey("MX-NAY"), Tz::America_Bahia_Banderas},
|
||||
{IsoCodes::subdivisionCodeToKey("MX-NLE"), Tz::America_Monterrey},
|
||||
{IsoCodes::subdivisionCodeToKey("MX-NLE"), Tz::America_Matamoros},
|
||||
{IsoCodes::subdivisionCodeToKey("MX-OAX"), Tz::America_Mexico_City},
|
||||
{IsoCodes::subdivisionCodeToKey("MX-PUE"), Tz::America_Mexico_City},
|
||||
{IsoCodes::subdivisionCodeToKey("MX-QUE"), Tz::America_Mexico_City},
|
||||
{IsoCodes::subdivisionCodeToKey("MX-ROO"), Tz::America_Cancun},
|
||||
{IsoCodes::subdivisionCodeToKey("MX-SIN"), Tz::America_Mazatlan},
|
||||
{IsoCodes::subdivisionCodeToKey("MX-SLP"), Tz::America_Mexico_City},
|
||||
{IsoCodes::subdivisionCodeToKey("MX-SON"), Tz::America_Hermosillo},
|
||||
{IsoCodes::subdivisionCodeToKey("MX-TAB"), Tz::America_Mexico_City},
|
||||
{IsoCodes::subdivisionCodeToKey("MX-TAM"), Tz::America_Monterrey},
|
||||
{IsoCodes::subdivisionCodeToKey("MX-TAM"), Tz::America_Matamoros},
|
||||
{IsoCodes::subdivisionCodeToKey("MX-TLA"), Tz::America_Mexico_City},
|
||||
{IsoCodes::subdivisionCodeToKey("MX-VER"), Tz::America_Mexico_City},
|
||||
{IsoCodes::subdivisionCodeToKey("MX-YUC"), Tz::America_Merida},
|
||||
{IsoCodes::subdivisionCodeToKey("MX-ZAC"), Tz::America_Mexico_City},
|
||||
{IsoCodes::subdivisionCodeToKey("NL-AW"), Tz::America_Aruba},
|
||||
{IsoCodes::subdivisionCodeToKey("NL-CW"), Tz::America_Curacao},
|
||||
{IsoCodes::subdivisionCodeToKey("NL-DR"), Tz::Europe_Amsterdam},
|
||||
{IsoCodes::subdivisionCodeToKey("NL-FL"), Tz::Europe_Amsterdam},
|
||||
{IsoCodes::subdivisionCodeToKey("NL-FR"), Tz::Europe_Amsterdam},
|
||||
{IsoCodes::subdivisionCodeToKey("NL-GE"), Tz::Europe_Amsterdam},
|
||||
{IsoCodes::subdivisionCodeToKey("NL-GR"), Tz::Europe_Amsterdam},
|
||||
{IsoCodes::subdivisionCodeToKey("NL-LI"), Tz::Europe_Amsterdam},
|
||||
{IsoCodes::subdivisionCodeToKey("NL-NB"), Tz::Europe_Amsterdam},
|
||||
{IsoCodes::subdivisionCodeToKey("NL-NH"), Tz::Europe_Amsterdam},
|
||||
{IsoCodes::subdivisionCodeToKey("NL-OV"), Tz::Europe_Amsterdam},
|
||||
{IsoCodes::subdivisionCodeToKey("NL-SX"), Tz::America_Lower_Princes},
|
||||
{IsoCodes::subdivisionCodeToKey("NL-UT"), Tz::Europe_Amsterdam},
|
||||
{IsoCodes::subdivisionCodeToKey("NL-ZE"), Tz::Europe_Amsterdam},
|
||||
{IsoCodes::subdivisionCodeToKey("NL-ZH"), Tz::Europe_Amsterdam},
|
||||
{IsoCodes::subdivisionCodeToKey("NZ-AUK"), Tz::Pacific_Auckland},
|
||||
{IsoCodes::subdivisionCodeToKey("NZ-BOP"), Tz::Pacific_Auckland},
|
||||
{IsoCodes::subdivisionCodeToKey("NZ-CAN"), Tz::Pacific_Auckland},
|
||||
{IsoCodes::subdivisionCodeToKey("NZ-CIT"), Tz::Pacific_Chatham},
|
||||
{IsoCodes::subdivisionCodeToKey("NZ-GIS"), Tz::Pacific_Auckland},
|
||||
{IsoCodes::subdivisionCodeToKey("NZ-HKB"), Tz::Pacific_Auckland},
|
||||
{IsoCodes::subdivisionCodeToKey("NZ-MBH"), Tz::Pacific_Auckland},
|
||||
{IsoCodes::subdivisionCodeToKey("NZ-MWT"), Tz::Pacific_Auckland},
|
||||
{IsoCodes::subdivisionCodeToKey("NZ-NSN"), Tz::Pacific_Auckland},
|
||||
{IsoCodes::subdivisionCodeToKey("NZ-NTL"), Tz::Pacific_Auckland},
|
||||
{IsoCodes::subdivisionCodeToKey("NZ-OTA"), Tz::Pacific_Auckland},
|
||||
{IsoCodes::subdivisionCodeToKey("NZ-STL"), Tz::Pacific_Auckland},
|
||||
{IsoCodes::subdivisionCodeToKey("NZ-TAS"), Tz::Pacific_Auckland},
|
||||
{IsoCodes::subdivisionCodeToKey("NZ-TKI"), Tz::Pacific_Auckland},
|
||||
{IsoCodes::subdivisionCodeToKey("NZ-WGN"), Tz::Pacific_Auckland},
|
||||
{IsoCodes::subdivisionCodeToKey("NZ-WKO"), Tz::Pacific_Auckland},
|
||||
{IsoCodes::subdivisionCodeToKey("NZ-WTC"), Tz::Pacific_Auckland},
|
||||
{IsoCodes::subdivisionCodeToKey("PG-CPK"), Tz::Pacific_Port_Moresby},
|
||||
{IsoCodes::subdivisionCodeToKey("PG-CPM"), Tz::Pacific_Port_Moresby},
|
||||
{IsoCodes::subdivisionCodeToKey("PG-EBR"), Tz::Pacific_Port_Moresby},
|
||||
{IsoCodes::subdivisionCodeToKey("PG-EHG"), Tz::Pacific_Port_Moresby},
|
||||
{IsoCodes::subdivisionCodeToKey("PG-EPW"), Tz::Pacific_Port_Moresby},
|
||||
{IsoCodes::subdivisionCodeToKey("PG-ESW"), Tz::Pacific_Port_Moresby},
|
||||
{IsoCodes::subdivisionCodeToKey("PG-GPK"), Tz::Pacific_Port_Moresby},
|
||||
{IsoCodes::subdivisionCodeToKey("PG-HLA"), Tz::Pacific_Port_Moresby},
|
||||
{IsoCodes::subdivisionCodeToKey("PG-JWK"), Tz::Pacific_Port_Moresby},
|
||||
{IsoCodes::subdivisionCodeToKey("PG-MBA"), Tz::Pacific_Port_Moresby},
|
||||
{IsoCodes::subdivisionCodeToKey("PG-MPL"), Tz::Pacific_Port_Moresby},
|
||||
{IsoCodes::subdivisionCodeToKey("PG-MPM"), Tz::Pacific_Port_Moresby},
|
||||
{IsoCodes::subdivisionCodeToKey("PG-MRL"), Tz::Pacific_Port_Moresby},
|
||||
{IsoCodes::subdivisionCodeToKey("PG-NCD"), Tz::Pacific_Port_Moresby},
|
||||
{IsoCodes::subdivisionCodeToKey("PG-NIK"), Tz::Pacific_Port_Moresby},
|
||||
{IsoCodes::subdivisionCodeToKey("PG-NIK"), Tz::Pacific_Bougainville},
|
||||
{IsoCodes::subdivisionCodeToKey("PG-NPP"), Tz::Pacific_Port_Moresby},
|
||||
{IsoCodes::subdivisionCodeToKey("PG-NSB"), Tz::Pacific_Bougainville},
|
||||
{IsoCodes::subdivisionCodeToKey("PG-SAN"), Tz::Pacific_Port_Moresby},
|
||||
{IsoCodes::subdivisionCodeToKey("PG-SHM"), Tz::Pacific_Port_Moresby},
|
||||
{IsoCodes::subdivisionCodeToKey("PG-WBK"), Tz::Pacific_Port_Moresby},
|
||||
{IsoCodes::subdivisionCodeToKey("PG-WHM"), Tz::Pacific_Port_Moresby},
|
||||
{IsoCodes::subdivisionCodeToKey("PG-WPD"), Tz::Pacific_Port_Moresby},
|
||||
{IsoCodes::subdivisionCodeToKey("PS-BTH"), Tz::Asia_Hebron},
|
||||
{IsoCodes::subdivisionCodeToKey("PS-BTH"), Tz::Asia_Jerusalem},
|
||||
{IsoCodes::subdivisionCodeToKey("PS-DEB"), Tz::Asia_Gaza},
|
||||
{IsoCodes::subdivisionCodeToKey("PS-GZA"), Tz::Asia_Gaza},
|
||||
{IsoCodes::subdivisionCodeToKey("PS-HBN"), Tz::Asia_Hebron},
|
||||
{IsoCodes::subdivisionCodeToKey("PS-HBN"), Tz::Asia_Jerusalem},
|
||||
{IsoCodes::subdivisionCodeToKey("PS-JEM"), Tz::Asia_Hebron},
|
||||
{IsoCodes::subdivisionCodeToKey("PS-JEM"), Tz::Asia_Jerusalem},
|
||||
{IsoCodes::subdivisionCodeToKey("PS-JEN"), Tz::Asia_Hebron},
|
||||
{IsoCodes::subdivisionCodeToKey("PS-JEN"), Tz::Asia_Jerusalem},
|
||||
{IsoCodes::subdivisionCodeToKey("PS-JRH"), Tz::Asia_Hebron},
|
||||
{IsoCodes::subdivisionCodeToKey("PS-JRH"), Tz::Asia_Jerusalem},
|
||||
{IsoCodes::subdivisionCodeToKey("PS-KYS"), Tz::Asia_Gaza},
|
||||
{IsoCodes::subdivisionCodeToKey("PS-NBS"), Tz::Asia_Hebron},
|
||||
{IsoCodes::subdivisionCodeToKey("PS-NBS"), Tz::Asia_Jerusalem},
|
||||
{IsoCodes::subdivisionCodeToKey("PS-NGZ"), Tz::Asia_Gaza},
|
||||
{IsoCodes::subdivisionCodeToKey("PS-QQA"), Tz::Asia_Hebron},
|
||||
{IsoCodes::subdivisionCodeToKey("PS-QQA"), Tz::Asia_Jerusalem},
|
||||
{IsoCodes::subdivisionCodeToKey("PS-RBH"), Tz::Asia_Hebron},
|
||||
{IsoCodes::subdivisionCodeToKey("PS-RBH"), Tz::Asia_Jerusalem},
|
||||
{IsoCodes::subdivisionCodeToKey("PS-RFH"), Tz::Asia_Gaza},
|
||||
{IsoCodes::subdivisionCodeToKey("PS-SLT"), Tz::Asia_Hebron},
|
||||
{IsoCodes::subdivisionCodeToKey("PS-SLT"), Tz::Asia_Jerusalem},
|
||||
{IsoCodes::subdivisionCodeToKey("PS-TBS"), Tz::Asia_Hebron},
|
||||
{IsoCodes::subdivisionCodeToKey("PS-TBS"), Tz::Asia_Jerusalem},
|
||||
{IsoCodes::subdivisionCodeToKey("PS-TKM"), Tz::Asia_Hebron},
|
||||
{IsoCodes::subdivisionCodeToKey("PS-TKM"), Tz::Asia_Jerusalem},
|
||||
{IsoCodes::subdivisionCodeToKey("PT-01"), Tz::Europe_Lisbon},
|
||||
{IsoCodes::subdivisionCodeToKey("PT-02"), Tz::Europe_Lisbon},
|
||||
{IsoCodes::subdivisionCodeToKey("PT-03"), Tz::Europe_Lisbon},
|
||||
{IsoCodes::subdivisionCodeToKey("PT-04"), Tz::Europe_Lisbon},
|
||||
{IsoCodes::subdivisionCodeToKey("PT-05"), Tz::Europe_Lisbon},
|
||||
{IsoCodes::subdivisionCodeToKey("PT-06"), Tz::Europe_Lisbon},
|
||||
{IsoCodes::subdivisionCodeToKey("PT-07"), Tz::Europe_Lisbon},
|
||||
{IsoCodes::subdivisionCodeToKey("PT-08"), Tz::Europe_Lisbon},
|
||||
{IsoCodes::subdivisionCodeToKey("PT-09"), Tz::Europe_Lisbon},
|
||||
{IsoCodes::subdivisionCodeToKey("PT-10"), Tz::Europe_Lisbon},
|
||||
{IsoCodes::subdivisionCodeToKey("PT-11"), Tz::Europe_Lisbon},
|
||||
{IsoCodes::subdivisionCodeToKey("PT-12"), Tz::Europe_Lisbon},
|
||||
{IsoCodes::subdivisionCodeToKey("PT-13"), Tz::Europe_Lisbon},
|
||||
{IsoCodes::subdivisionCodeToKey("PT-14"), Tz::Europe_Lisbon},
|
||||
{IsoCodes::subdivisionCodeToKey("PT-15"), Tz::Europe_Lisbon},
|
||||
{IsoCodes::subdivisionCodeToKey("PT-16"), Tz::Europe_Lisbon},
|
||||
{IsoCodes::subdivisionCodeToKey("PT-17"), Tz::Europe_Lisbon},
|
||||
{IsoCodes::subdivisionCodeToKey("PT-18"), Tz::Europe_Lisbon},
|
||||
{IsoCodes::subdivisionCodeToKey("PT-20"), Tz::Atlantic_Azores},
|
||||
{IsoCodes::subdivisionCodeToKey("PT-30"), Tz::Atlantic_Madeira},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-AD"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-AL"), Tz::Asia_Barnaul},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-ALT"), Tz::Asia_Barnaul},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-AMU"), Tz::Asia_Yakutsk},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-ARK"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-AST"), Tz::Europe_Astrakhan},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-BA"), Tz::Asia_Yekaterinburg},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-BEL"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-BRY"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-BU"), Tz::Asia_Irkutsk},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-CE"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-CHE"), Tz::Asia_Yekaterinburg},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-CHU"), Tz::Asia_Anadyr},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-CU"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-DA"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-EAO"), Tz::Asia_Krasnoyarsk},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-IN"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-IRK"), Tz::Asia_Irkutsk},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-IVA"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-KAM"), Tz::Asia_Kamchatka},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-KB"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-KC"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-KDA"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-KEM"), Tz::Asia_Novokuznetsk},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-KGD"), Tz::Europe_Kaliningrad},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-KGN"), Tz::Asia_Yekaterinburg},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-KHA"), Tz::Asia_Vladivostok},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-KHM"), Tz::Asia_Yekaterinburg},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-KIR"), Tz::Europe_Kirov},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-KK"), Tz::Asia_Krasnoyarsk},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-KL"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-KLU"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-KO"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-KOS"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-KR"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-KRS"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-KYA"), Tz::Asia_Krasnoyarsk},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-LEN"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-LIP"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-MAG"), Tz::Asia_Magadan},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-ME"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-MO"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-MOS"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-MOW"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-MUR"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-NEN"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-NGR"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-NIZ"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-NVS"), Tz::Asia_Novosibirsk},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-OMS"), Tz::Asia_Omsk},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-ORE"), Tz::Asia_Yekaterinburg},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-ORL"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-PER"), Tz::Asia_Yekaterinburg},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-PNZ"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-PRI"), Tz::Asia_Vladivostok},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-PSK"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-ROS"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-RYA"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-SA"), Tz::Asia_Yakutsk},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-SA"), Tz::Asia_Srednekolymsk},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-SA"), Tz::Asia_Vladivostok},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-SA"), Tz::Asia_Khandyga},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-SA"), Tz::Asia_Ust_Nera},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-SAK"), Tz::Asia_Sakhalin},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-SAK"), Tz::Asia_Ust_Nera},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-SAK"), Tz::Asia_Srednekolymsk},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-SAM"), Tz::Europe_Samara},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-SAR"), Tz::Europe_Saratov},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-SE"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-SMO"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-SPE"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-STA"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-SVE"), Tz::Asia_Yekaterinburg},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-TA"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-TAM"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-TOM"), Tz::Asia_Tomsk},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-TUL"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-TVE"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-TY"), Tz::Asia_Krasnoyarsk},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-TYU"), Tz::Asia_Yekaterinburg},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-UD"), Tz::Europe_Samara},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-ULY"), Tz::Europe_Ulyanovsk},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-VGG"), Tz::Europe_Volgograd},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-VLA"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-VLG"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-VOR"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-YAN"), Tz::Asia_Yekaterinburg},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-YAR"), Tz::Europe_Moscow},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-YEV"), Tz::Asia_Vladivostok},
|
||||
{IsoCodes::subdivisionCodeToKey("RU-ZAB"), Tz::Asia_Chita},
|
||||
{IsoCodes::subdivisionCodeToKey("SD-DC"), Tz::Africa_Khartoum},
|
||||
{IsoCodes::subdivisionCodeToKey("SD-DE"), Tz::Africa_Khartoum},
|
||||
{IsoCodes::subdivisionCodeToKey("SD-DN"), Tz::Africa_Khartoum},
|
||||
{IsoCodes::subdivisionCodeToKey("SD-DS"), Tz::Africa_Khartoum},
|
||||
{IsoCodes::subdivisionCodeToKey("SD-DW"), Tz::Africa_Khartoum},
|
||||
{IsoCodes::subdivisionCodeToKey("SD-GD"), Tz::Africa_Khartoum},
|
||||
{IsoCodes::subdivisionCodeToKey("SD-GK"), Tz::Africa_Khartoum},
|
||||
{IsoCodes::subdivisionCodeToKey("SD-GK"), Tz::Africa_Juba},
|
||||
{IsoCodes::subdivisionCodeToKey("SD-GZ"), Tz::Africa_Khartoum},
|
||||
{IsoCodes::subdivisionCodeToKey("SD-KA"), Tz::Africa_Khartoum},
|
||||
{IsoCodes::subdivisionCodeToKey("SD-KH"), Tz::Africa_Khartoum},
|
||||
{IsoCodes::subdivisionCodeToKey("SD-KN"), Tz::Africa_Khartoum},
|
||||
{IsoCodes::subdivisionCodeToKey("SD-KS"), Tz::Africa_Khartoum},
|
||||
{IsoCodes::subdivisionCodeToKey("SD-NB"), Tz::Africa_Khartoum},
|
||||
{IsoCodes::subdivisionCodeToKey("SD-NO"), Tz::Africa_Khartoum},
|
||||
{IsoCodes::subdivisionCodeToKey("SD-NR"), Tz::Africa_Khartoum},
|
||||
{IsoCodes::subdivisionCodeToKey("SD-NW"), Tz::Africa_Khartoum},
|
||||
{IsoCodes::subdivisionCodeToKey("SD-RS"), Tz::Africa_Khartoum},
|
||||
{IsoCodes::subdivisionCodeToKey("SD-SI"), Tz::Africa_Khartoum},
|
||||
{IsoCodes::subdivisionCodeToKey("SS-BN"), Tz::Africa_Juba},
|
||||
{IsoCodes::subdivisionCodeToKey("SS-BW"), Tz::Africa_Juba},
|
||||
{IsoCodes::subdivisionCodeToKey("SS-BW"), Tz::Africa_Khartoum},
|
||||
{IsoCodes::subdivisionCodeToKey("SS-EC"), Tz::Africa_Juba},
|
||||
{IsoCodes::subdivisionCodeToKey("SS-EE"), Tz::Africa_Juba},
|
||||
{IsoCodes::subdivisionCodeToKey("SS-EW"), Tz::Africa_Juba},
|
||||
{IsoCodes::subdivisionCodeToKey("SS-JG"), Tz::Africa_Juba},
|
||||
{IsoCodes::subdivisionCodeToKey("SS-LK"), Tz::Africa_Juba},
|
||||
{IsoCodes::subdivisionCodeToKey("SS-NU"), Tz::Africa_Juba},
|
||||
{IsoCodes::subdivisionCodeToKey("SS-UY"), Tz::Africa_Juba},
|
||||
{IsoCodes::subdivisionCodeToKey("SS-WR"), Tz::Africa_Juba},
|
||||
{IsoCodes::subdivisionCodeToKey("SS-WR"), Tz::Africa_Khartoum},
|
||||
{IsoCodes::subdivisionCodeToKey("UA-05"), Tz::Europe_Kiev},
|
||||
{IsoCodes::subdivisionCodeToKey("UA-07"), Tz::Europe_Kiev},
|
||||
{IsoCodes::subdivisionCodeToKey("UA-09"), Tz::Europe_Kiev},
|
||||
{IsoCodes::subdivisionCodeToKey("UA-12"), Tz::Europe_Kiev},
|
||||
{IsoCodes::subdivisionCodeToKey("UA-14"), Tz::Europe_Kiev},
|
||||
{IsoCodes::subdivisionCodeToKey("UA-18"), Tz::Europe_Kiev},
|
||||
{IsoCodes::subdivisionCodeToKey("UA-21"), Tz::Europe_Uzhgorod},
|
||||
{IsoCodes::subdivisionCodeToKey("UA-23"), Tz::Europe_Zaporozhye},
|
||||
{IsoCodes::subdivisionCodeToKey("UA-26"), Tz::Europe_Kiev},
|
||||
{IsoCodes::subdivisionCodeToKey("UA-30"), Tz::Europe_Kiev},
|
||||
{IsoCodes::subdivisionCodeToKey("UA-32"), Tz::Europe_Kiev},
|
||||
{IsoCodes::subdivisionCodeToKey("UA-35"), Tz::Europe_Kiev},
|
||||
{IsoCodes::subdivisionCodeToKey("UA-40"), Tz::Europe_Simferopol},
|
||||
{IsoCodes::subdivisionCodeToKey("UA-43"), Tz::Europe_Simferopol},
|
||||
{IsoCodes::subdivisionCodeToKey("UA-46"), Tz::Europe_Kiev},
|
||||
{IsoCodes::subdivisionCodeToKey("UA-48"), Tz::Europe_Kiev},
|
||||
{IsoCodes::subdivisionCodeToKey("UA-51"), Tz::Europe_Kiev},
|
||||
{IsoCodes::subdivisionCodeToKey("UA-53"), Tz::Europe_Kiev},
|
||||
{IsoCodes::subdivisionCodeToKey("UA-56"), Tz::Europe_Kiev},
|
||||
{IsoCodes::subdivisionCodeToKey("UA-59"), Tz::Europe_Kiev},
|
||||
{IsoCodes::subdivisionCodeToKey("UA-61"), Tz::Europe_Kiev},
|
||||
{IsoCodes::subdivisionCodeToKey("UA-63"), Tz::Europe_Kiev},
|
||||
{IsoCodes::subdivisionCodeToKey("UA-65"), Tz::Europe_Kiev},
|
||||
{IsoCodes::subdivisionCodeToKey("UA-68"), Tz::Europe_Kiev},
|
||||
{IsoCodes::subdivisionCodeToKey("UA-71"), Tz::Europe_Kiev},
|
||||
{IsoCodes::subdivisionCodeToKey("UA-74"), Tz::Europe_Kiev},
|
||||
{IsoCodes::subdivisionCodeToKey("UA-77"), Tz::Europe_Kiev},
|
||||
{IsoCodes::subdivisionCodeToKey("UM-67"), Tz::Pacific_Honolulu},
|
||||
{IsoCodes::subdivisionCodeToKey("UM-71"), Tz::Pacific_Midway},
|
||||
{IsoCodes::subdivisionCodeToKey("UM-76"), Tz::America_Port_au_Prince},
|
||||
{IsoCodes::subdivisionCodeToKey("UM-79"), Tz::Pacific_Wake},
|
||||
// UM-81
|
||||
// UM-84
|
||||
// UM-86
|
||||
// UM-89
|
||||
// UM-95
|
||||
{IsoCodes::subdivisionCodeToKey("US-AK"), Tz::America_Anchorage},
|
||||
{IsoCodes::subdivisionCodeToKey("US-AK"), Tz::America_Nome},
|
||||
{IsoCodes::subdivisionCodeToKey("US-AK"), Tz::America_Sitka},
|
||||
{IsoCodes::subdivisionCodeToKey("US-AK"), Tz::America_Adak},
|
||||
{IsoCodes::subdivisionCodeToKey("US-AK"), Tz::America_Juneau},
|
||||
{IsoCodes::subdivisionCodeToKey("US-AK"), Tz::America_Yakutat},
|
||||
{IsoCodes::subdivisionCodeToKey("US-AK"), Tz::America_Metlakatla},
|
||||
{IsoCodes::subdivisionCodeToKey("US-AL"), Tz::America_Chicago},
|
||||
{IsoCodes::subdivisionCodeToKey("US-AR"), Tz::America_Chicago},
|
||||
{IsoCodes::subdivisionCodeToKey("US-AS"), Tz::Pacific_Pago_Pago},
|
||||
{IsoCodes::subdivisionCodeToKey("US-AZ"), Tz::America_Phoenix},
|
||||
{IsoCodes::subdivisionCodeToKey("US-AZ"), Tz::America_Denver},
|
||||
{IsoCodes::subdivisionCodeToKey("US-CA"), Tz::America_Los_Angeles},
|
||||
{IsoCodes::subdivisionCodeToKey("US-CO"), Tz::America_Denver},
|
||||
{IsoCodes::subdivisionCodeToKey("US-CT"), Tz::America_New_York},
|
||||
{IsoCodes::subdivisionCodeToKey("US-DC"), Tz::America_New_York},
|
||||
{IsoCodes::subdivisionCodeToKey("US-DE"), Tz::America_New_York},
|
||||
{IsoCodes::subdivisionCodeToKey("US-FL"), Tz::America_New_York},
|
||||
{IsoCodes::subdivisionCodeToKey("US-FL"), Tz::America_Chicago},
|
||||
{IsoCodes::subdivisionCodeToKey("US-GA"), Tz::America_New_York},
|
||||
{IsoCodes::subdivisionCodeToKey("US-GU"), Tz::Pacific_Guam},
|
||||
{IsoCodes::subdivisionCodeToKey("US-HI"), Tz::Pacific_Honolulu},
|
||||
{IsoCodes::subdivisionCodeToKey("US-HI"), Tz::Pacific_Midway},
|
||||
{IsoCodes::subdivisionCodeToKey("US-IA"), Tz::America_Chicago},
|
||||
{IsoCodes::subdivisionCodeToKey("US-ID"), Tz::America_Boise},
|
||||
{IsoCodes::subdivisionCodeToKey("US-ID"), Tz::America_Los_Angeles},
|
||||
{IsoCodes::subdivisionCodeToKey("US-IL"), Tz::America_Chicago},
|
||||
{IsoCodes::subdivisionCodeToKey("US-IN"), Tz::America_Indiana_Indianapolis},
|
||||
{IsoCodes::subdivisionCodeToKey("US-IN"), Tz::America_Chicago},
|
||||
{IsoCodes::subdivisionCodeToKey("US-IN"), Tz::America_Indiana_Vincennes},
|
||||
{IsoCodes::subdivisionCodeToKey("US-IN"), Tz::America_Kentucky_Louisville},
|
||||
{IsoCodes::subdivisionCodeToKey("US-IN"), Tz::America_Indiana_Winamac},
|
||||
{IsoCodes::subdivisionCodeToKey("US-IN"), Tz::America_Indiana_Tell_City},
|
||||
{IsoCodes::subdivisionCodeToKey("US-IN"), Tz::America_Indiana_Petersburg},
|
||||
{IsoCodes::subdivisionCodeToKey("US-IN"), Tz::America_Indiana_Knox},
|
||||
{IsoCodes::subdivisionCodeToKey("US-IN"), Tz::America_Indiana_Marengo},
|
||||
{IsoCodes::subdivisionCodeToKey("US-IN"), Tz::America_Indiana_Vevay},
|
||||
{IsoCodes::subdivisionCodeToKey("US-KS"), Tz::America_Chicago},
|
||||
{IsoCodes::subdivisionCodeToKey("US-KY"), Tz::America_New_York},
|
||||
{IsoCodes::subdivisionCodeToKey("US-KY"), Tz::America_Chicago},
|
||||
{IsoCodes::subdivisionCodeToKey("US-KY"), Tz::America_Kentucky_Monticello},
|
||||
{IsoCodes::subdivisionCodeToKey("US-KY"), Tz::America_Kentucky_Louisville},
|
||||
{IsoCodes::subdivisionCodeToKey("US-LA"), Tz::America_Chicago},
|
||||
{IsoCodes::subdivisionCodeToKey("US-MA"), Tz::America_New_York},
|
||||
{IsoCodes::subdivisionCodeToKey("US-MD"), Tz::America_New_York},
|
||||
{IsoCodes::subdivisionCodeToKey("US-ME"), Tz::America_New_York},
|
||||
{IsoCodes::subdivisionCodeToKey("US-MI"), Tz::America_Detroit},
|
||||
{IsoCodes::subdivisionCodeToKey("US-MI"), Tz::America_Menominee},
|
||||
{IsoCodes::subdivisionCodeToKey("US-MN"), Tz::America_Chicago},
|
||||
{IsoCodes::subdivisionCodeToKey("US-MO"), Tz::America_Chicago},
|
||||
{IsoCodes::subdivisionCodeToKey("US-MP"), Tz::Pacific_Saipan},
|
||||
{IsoCodes::subdivisionCodeToKey("US-MS"), Tz::America_Chicago},
|
||||
{IsoCodes::subdivisionCodeToKey("US-MT"), Tz::America_Denver},
|
||||
{IsoCodes::subdivisionCodeToKey("US-NC"), Tz::America_New_York},
|
||||
{IsoCodes::subdivisionCodeToKey("US-ND"), Tz::America_Chicago},
|
||||
{IsoCodes::subdivisionCodeToKey("US-ND"), Tz::America_Denver},
|
||||
{IsoCodes::subdivisionCodeToKey("US-ND"), Tz::America_North_Dakota_New_Salem},
|
||||
{IsoCodes::subdivisionCodeToKey("US-ND"), Tz::America_North_Dakota_Beulah},
|
||||
{IsoCodes::subdivisionCodeToKey("US-ND"), Tz::America_North_Dakota_Center},
|
||||
{IsoCodes::subdivisionCodeToKey("US-NE"), Tz::America_Chicago},
|
||||
{IsoCodes::subdivisionCodeToKey("US-NE"), Tz::America_Denver},
|
||||
{IsoCodes::subdivisionCodeToKey("US-NH"), Tz::America_New_York},
|
||||
{IsoCodes::subdivisionCodeToKey("US-NJ"), Tz::America_New_York},
|
||||
{IsoCodes::subdivisionCodeToKey("US-NM"), Tz::America_Denver},
|
||||
{IsoCodes::subdivisionCodeToKey("US-NV"), Tz::America_Los_Angeles},
|
||||
{IsoCodes::subdivisionCodeToKey("US-NY"), Tz::America_New_York},
|
||||
{IsoCodes::subdivisionCodeToKey("US-OH"), Tz::America_New_York},
|
||||
{IsoCodes::subdivisionCodeToKey("US-OK"), Tz::America_Chicago},
|
||||
{IsoCodes::subdivisionCodeToKey("US-OR"), Tz::America_Los_Angeles},
|
||||
{IsoCodes::subdivisionCodeToKey("US-OR"), Tz::America_Boise},
|
||||
{IsoCodes::subdivisionCodeToKey("US-PA"), Tz::America_New_York},
|
||||
{IsoCodes::subdivisionCodeToKey("US-PR"), Tz::America_Puerto_Rico},
|
||||
{IsoCodes::subdivisionCodeToKey("US-RI"), Tz::America_New_York},
|
||||
{IsoCodes::subdivisionCodeToKey("US-SC"), Tz::America_New_York},
|
||||
{IsoCodes::subdivisionCodeToKey("US-SD"), Tz::America_Chicago},
|
||||
{IsoCodes::subdivisionCodeToKey("US-SD"), Tz::America_Denver},
|
||||
{IsoCodes::subdivisionCodeToKey("US-TN"), Tz::America_Chicago},
|
||||
{IsoCodes::subdivisionCodeToKey("US-TN"), Tz::America_New_York},
|
||||
{IsoCodes::subdivisionCodeToKey("US-TX"), Tz::America_Chicago},
|
||||
{IsoCodes::subdivisionCodeToKey("US-UM"), Tz::Pacific_Honolulu},
|
||||
{IsoCodes::subdivisionCodeToKey("US-UM"), Tz::Pacific_Midway},
|
||||
{IsoCodes::subdivisionCodeToKey("US-UM"), Tz::Pacific_Wake},
|
||||
{IsoCodes::subdivisionCodeToKey("US-UM"), Tz::America_Port_au_Prince},
|
||||
{IsoCodes::subdivisionCodeToKey("US-UT"), Tz::America_Denver},
|
||||
{IsoCodes::subdivisionCodeToKey("US-VA"), Tz::America_New_York},
|
||||
{IsoCodes::subdivisionCodeToKey("US-VI"), Tz::America_St_Thomas},
|
||||
{IsoCodes::subdivisionCodeToKey("US-VT"), Tz::America_New_York},
|
||||
{IsoCodes::subdivisionCodeToKey("US-WA"), Tz::America_Los_Angeles},
|
||||
{IsoCodes::subdivisionCodeToKey("US-WI"), Tz::America_Chicago},
|
||||
{IsoCodes::subdivisionCodeToKey("US-WV"), Tz::America_New_York},
|
||||
{IsoCodes::subdivisionCodeToKey("US-WY"), Tz::America_Denver},
|
||||
{IsoCodes::subdivisionCodeToKey("UZ-AN"), Tz::Asia_Tashkent},
|
||||
{IsoCodes::subdivisionCodeToKey("UZ-BU"), Tz::Asia_Samarkand},
|
||||
{IsoCodes::subdivisionCodeToKey("UZ-FA"), Tz::Asia_Tashkent},
|
||||
{IsoCodes::subdivisionCodeToKey("UZ-JI"), Tz::Asia_Tashkent},
|
||||
{IsoCodes::subdivisionCodeToKey("UZ-NG"), Tz::Asia_Tashkent},
|
||||
{IsoCodes::subdivisionCodeToKey("UZ-NW"), Tz::Asia_Samarkand},
|
||||
{IsoCodes::subdivisionCodeToKey("UZ-QA"), Tz::Asia_Samarkand},
|
||||
{IsoCodes::subdivisionCodeToKey("UZ-QR"), Tz::Asia_Samarkand},
|
||||
{IsoCodes::subdivisionCodeToKey("UZ-SA"), Tz::Asia_Samarkand},
|
||||
{IsoCodes::subdivisionCodeToKey("UZ-SI"), Tz::Asia_Tashkent},
|
||||
{IsoCodes::subdivisionCodeToKey("UZ-SU"), Tz::Asia_Samarkand},
|
||||
{IsoCodes::subdivisionCodeToKey("UZ-TK"), Tz::Asia_Tashkent},
|
||||
{IsoCodes::subdivisionCodeToKey("UZ-TO"), Tz::Asia_Tashkent},
|
||||
{IsoCodes::subdivisionCodeToKey("UZ-XO"), Tz::Asia_Samarkand},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-01"), Tz::Asia_Bangkok},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-02"), Tz::Asia_Bangkok},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-03"), Tz::Asia_Bangkok},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-04"), Tz::Asia_Bangkok},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-05"), Tz::Asia_Bangkok},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-06"), Tz::Asia_Bangkok},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-07"), Tz::Asia_Bangkok},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-09"), Tz::Asia_Bangkok},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-13"), Tz::Asia_Bangkok},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-14"), Tz::Asia_Bangkok},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-18"), Tz::Asia_Bangkok},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-20"), Tz::Asia_Bangkok},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-21"), Tz::Asia_Bangkok},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-22"), Tz::Asia_Bangkok},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-23"), Tz::Asia_Bangkok},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-24"), Tz::Asia_Bangkok},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-25"), Tz::Asia_Ho_Chi_Minh},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-26"), Tz::Asia_Ho_Chi_Minh},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-27"), Tz::Asia_Ho_Chi_Minh},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-28"), Tz::Asia_Ho_Chi_Minh},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-29"), Tz::Asia_Ho_Chi_Minh},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-30"), Tz::Asia_Ho_Chi_Minh},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-31"), Tz::Asia_Ho_Chi_Minh},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-32"), Tz::Asia_Ho_Chi_Minh},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-33"), Tz::Asia_Ho_Chi_Minh},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-34"), Tz::Asia_Ho_Chi_Minh},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-35"), Tz::Asia_Ho_Chi_Minh},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-36"), Tz::Asia_Ho_Chi_Minh},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-37"), Tz::Asia_Ho_Chi_Minh},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-39"), Tz::Asia_Ho_Chi_Minh},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-40"), Tz::Asia_Ho_Chi_Minh},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-41"), Tz::Asia_Ho_Chi_Minh},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-43"), Tz::Asia_Ho_Chi_Minh},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-44"), Tz::Asia_Ho_Chi_Minh},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-45"), Tz::Asia_Ho_Chi_Minh},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-46"), Tz::Asia_Ho_Chi_Minh},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-47"), Tz::Asia_Ho_Chi_Minh},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-49"), Tz::Asia_Ho_Chi_Minh},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-50"), Tz::Asia_Ho_Chi_Minh},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-51"), Tz::Asia_Ho_Chi_Minh},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-52"), Tz::Asia_Ho_Chi_Minh},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-53"), Tz::Asia_Bangkok},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-54"), Tz::Asia_Bangkok},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-55"), Tz::Asia_Ho_Chi_Minh},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-56"), Tz::Asia_Bangkok},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-57"), Tz::Asia_Ho_Chi_Minh},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-58"), Tz::Asia_Ho_Chi_Minh},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-59"), Tz::Asia_Ho_Chi_Minh},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-61"), Tz::Asia_Bangkok},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-63"), Tz::Asia_Bangkok},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-66"), Tz::Asia_Bangkok},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-67"), Tz::Asia_Bangkok},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-68"), Tz::Asia_Bangkok},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-69"), Tz::Asia_Bangkok},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-70"), Tz::Asia_Bangkok},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-71"), Tz::Asia_Bangkok},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-72"), Tz::Asia_Ho_Chi_Minh},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-73"), Tz::Asia_Ho_Chi_Minh},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-CT"), Tz::Asia_Ho_Chi_Minh},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-DN"), Tz::Asia_Ho_Chi_Minh},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-HN"), Tz::Asia_Bangkok},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-HP"), Tz::Asia_Bangkok},
|
||||
{IsoCodes::subdivisionCodeToKey("VN-SG"), Tz::Asia_Ho_Chi_Minh},
|
||||
};
|
||||
@@ -0,0 +1,434 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: ODbL-1.0
|
||||
* SPDX-FileCopyrightText: OpenStreetMap contributors
|
||||
*
|
||||
* Autogenerated using QGIS - do not edit!
|
||||
*/
|
||||
|
||||
static constexpr const char timezone_name_table[] =
|
||||
"Africa/Abidjan\0"
|
||||
"Africa/Accra\0"
|
||||
"Africa/Addis_Ababa\0"
|
||||
"Africa/Algiers\0"
|
||||
"Africa/Asmara\0"
|
||||
"Africa/Bamako\0"
|
||||
"Africa/Bangui\0"
|
||||
"Africa/Banjul\0"
|
||||
"Africa/Bissau\0"
|
||||
"Africa/Blantyre\0"
|
||||
"Africa/Brazzaville\0"
|
||||
"Africa/Bujumbura\0"
|
||||
"Africa/Cairo\0"
|
||||
"Africa/Casablanca\0"
|
||||
"Africa/Ceuta\0"
|
||||
"Africa/Conakry\0"
|
||||
"Africa/Dakar\0"
|
||||
"Africa/Dar_es_Salaam\0"
|
||||
"Africa/Djibouti\0"
|
||||
"Africa/Douala\0"
|
||||
"Africa/El_Aaiun\0"
|
||||
"Africa/Freetown\0"
|
||||
"Africa/Gaborone\0"
|
||||
"Africa/Harare\0"
|
||||
"Africa/Johannesburg\0"
|
||||
"Africa/Juba\0"
|
||||
"Africa/Kampala\0"
|
||||
"Africa/Khartoum\0"
|
||||
"Africa/Kigali\0"
|
||||
"Africa/Kinshasa\0"
|
||||
"Africa/Lagos\0"
|
||||
"Africa/Libreville\0"
|
||||
"Africa/Lome\0"
|
||||
"Africa/Luanda\0"
|
||||
"Africa/Lubumbashi\0"
|
||||
"Africa/Lusaka\0"
|
||||
"Africa/Malabo\0"
|
||||
"Africa/Maputo\0"
|
||||
"Africa/Maseru\0"
|
||||
"Africa/Mbabane\0"
|
||||
"Africa/Mogadishu\0"
|
||||
"Africa/Monrovia\0"
|
||||
"Africa/Nairobi\0"
|
||||
"Africa/Ndjamena\0"
|
||||
"Africa/Niamey\0"
|
||||
"Africa/Nouakchott\0"
|
||||
"Africa/Ouagadougou\0"
|
||||
"Africa/Porto-Novo\0"
|
||||
"Africa/Sao_Tome\0"
|
||||
"Africa/Tripoli\0"
|
||||
"Africa/Tunis\0"
|
||||
"Africa/Windhoek\0"
|
||||
"America/Adak\0"
|
||||
"America/Anchorage\0"
|
||||
"America/Anguilla\0"
|
||||
"America/Antigua\0"
|
||||
"America/Araguaina\0"
|
||||
"America/Argentina/Buenos_Aires\0"
|
||||
"America/Argentina/Catamarca\0"
|
||||
"America/Argentina/Cordoba\0"
|
||||
"America/Argentina/Jujuy\0"
|
||||
"America/Argentina/La_Rioja\0"
|
||||
"America/Argentina/Mendoza\0"
|
||||
"America/Argentina/Rio_Gallegos\0"
|
||||
"America/Argentina/Salta\0"
|
||||
"America/Argentina/San_Juan\0"
|
||||
"America/Argentina/San_Luis\0"
|
||||
"America/Argentina/Tucuman\0"
|
||||
"America/Argentina/Ushuaia\0"
|
||||
"America/Aruba\0"
|
||||
"America/Asuncion\0"
|
||||
"America/Atikokan\0"
|
||||
"America/Bahia\0"
|
||||
"America/Bahia_Banderas\0"
|
||||
"America/Barbados\0"
|
||||
"America/Belem\0"
|
||||
"America/Belize\0"
|
||||
"America/Blanc-Sablon\0"
|
||||
"America/Boa_Vista\0"
|
||||
"America/Bogota\0"
|
||||
"America/Boise\0"
|
||||
"America/Cambridge_Bay\0"
|
||||
"America/Campo_Grande\0"
|
||||
"America/Cancun\0"
|
||||
"America/Caracas\0"
|
||||
"America/Cayenne\0"
|
||||
"America/Cayman\0"
|
||||
"America/Chicago\0"
|
||||
"America/Chihuahua\0"
|
||||
"America/Costa_Rica\0"
|
||||
"America/Creston\0"
|
||||
"America/Cuiaba\0"
|
||||
"America/Curacao\0"
|
||||
"America/Danmarkshavn\0"
|
||||
"America/Dawson\0"
|
||||
"America/Dawson_Creek\0"
|
||||
"America/Denver\0"
|
||||
"America/Detroit\0"
|
||||
"America/Dominica\0"
|
||||
"America/Edmonton\0"
|
||||
"America/Eirunepe\0"
|
||||
"America/El_Salvador\0"
|
||||
"America/Fort_Nelson\0"
|
||||
"America/Fortaleza\0"
|
||||
"America/Glace_Bay\0"
|
||||
"America/Goose_Bay\0"
|
||||
"America/Grand_Turk\0"
|
||||
"America/Grenada\0"
|
||||
"America/Guadeloupe\0"
|
||||
"America/Guatemala\0"
|
||||
"America/Guayaquil\0"
|
||||
"America/Guyana\0"
|
||||
"America/Halifax\0"
|
||||
"America/Havana\0"
|
||||
"America/Hermosillo\0"
|
||||
"America/Indiana/Indianapolis\0"
|
||||
"America/Indiana/Knox\0"
|
||||
"America/Indiana/Marengo\0"
|
||||
"America/Indiana/Petersburg\0"
|
||||
"America/Indiana/Tell_City\0"
|
||||
"America/Indiana/Vevay\0"
|
||||
"America/Indiana/Vincennes\0"
|
||||
"America/Indiana/Winamac\0"
|
||||
"America/Inuvik\0"
|
||||
"America/Iqaluit\0"
|
||||
"America/Jamaica\0"
|
||||
"America/Juneau\0"
|
||||
"America/Kentucky/Louisville\0"
|
||||
"America/Kentucky/Monticello\0"
|
||||
"America/Kralendijk\0"
|
||||
"America/La_Paz\0"
|
||||
"America/Lima\0"
|
||||
"America/Los_Angeles\0"
|
||||
"America/Lower_Princes\0"
|
||||
"America/Maceio\0"
|
||||
"America/Managua\0"
|
||||
"America/Manaus\0"
|
||||
"America/Marigot\0"
|
||||
"America/Martinique\0"
|
||||
"America/Matamoros\0"
|
||||
"America/Mazatlan\0"
|
||||
"America/Menominee\0"
|
||||
"America/Merida\0"
|
||||
"America/Metlakatla\0"
|
||||
"America/Mexico_City\0"
|
||||
"America/Miquelon\0"
|
||||
"America/Moncton\0"
|
||||
"America/Monterrey\0"
|
||||
"America/Montevideo\0"
|
||||
"America/Montserrat\0"
|
||||
"America/Nassau\0"
|
||||
"America/New_York\0"
|
||||
"America/Nipigon\0"
|
||||
"America/Nome\0"
|
||||
"America/Noronha\0"
|
||||
"America/North_Dakota/Beulah\0"
|
||||
"America/North_Dakota/Center\0"
|
||||
"America/North_Dakota/New_Salem\0"
|
||||
"America/Nuuk\0"
|
||||
"America/Ojinaga\0"
|
||||
"America/Panama\0"
|
||||
"America/Pangnirtung\0"
|
||||
"America/Paramaribo\0"
|
||||
"America/Phoenix\0"
|
||||
"America/Port-au-Prince\0"
|
||||
"America/Port_of_Spain\0"
|
||||
"America/Porto_Velho\0"
|
||||
"America/Puerto_Rico\0"
|
||||
"America/Punta_Arenas\0"
|
||||
"America/Rainy_River\0"
|
||||
"America/Rankin_Inlet\0"
|
||||
"America/Recife\0"
|
||||
"America/Regina\0"
|
||||
"America/Resolute\0"
|
||||
"America/Rio_Branco\0"
|
||||
"America/Santarem\0"
|
||||
"America/Santiago\0"
|
||||
"America/Santo_Domingo\0"
|
||||
"America/Sao_Paulo\0"
|
||||
"America/Scoresbysund\0"
|
||||
"America/Sitka\0"
|
||||
"America/St_Barthelemy\0"
|
||||
"America/St_Johns\0"
|
||||
"America/St_Kitts\0"
|
||||
"America/St_Lucia\0"
|
||||
"America/St_Thomas\0"
|
||||
"America/St_Vincent\0"
|
||||
"America/Swift_Current\0"
|
||||
"America/Tegucigalpa\0"
|
||||
"America/Thule\0"
|
||||
"America/Thunder_Bay\0"
|
||||
"America/Tijuana\0"
|
||||
"America/Toronto\0"
|
||||
"America/Tortola\0"
|
||||
"America/Vancouver\0"
|
||||
"America/Whitehorse\0"
|
||||
"America/Winnipeg\0"
|
||||
"America/Yakutat\0"
|
||||
"America/Yellowknife\0"
|
||||
"Antarctica/Casey\0"
|
||||
"Antarctica/Davis\0"
|
||||
"Antarctica/DumontDUrville\0"
|
||||
"Antarctica/Macquarie\0"
|
||||
"Antarctica/Mawson\0"
|
||||
"Antarctica/McMurdo\0"
|
||||
"Antarctica/Palmer\0"
|
||||
"Antarctica/Rothera\0"
|
||||
"Antarctica/Syowa\0"
|
||||
"Antarctica/Troll\0"
|
||||
"Antarctica/Vostok\0"
|
||||
"Arctic/Longyearbyen\0"
|
||||
"Asia/Aden\0"
|
||||
"Asia/Almaty\0"
|
||||
"Asia/Amman\0"
|
||||
"Asia/Anadyr\0"
|
||||
"Asia/Aqtau\0"
|
||||
"Asia/Aqtobe\0"
|
||||
"Asia/Ashgabat\0"
|
||||
"Asia/Atyrau\0"
|
||||
"Asia/Baghdad\0"
|
||||
"Asia/Bahrain\0"
|
||||
"Asia/Baku\0"
|
||||
"Asia/Bangkok\0"
|
||||
"Asia/Barnaul\0"
|
||||
"Asia/Beirut\0"
|
||||
"Asia/Bishkek\0"
|
||||
"Asia/Brunei\0"
|
||||
"Asia/Chita\0"
|
||||
"Asia/Choibalsan\0"
|
||||
"Asia/Colombo\0"
|
||||
"Asia/Damascus\0"
|
||||
"Asia/Dhaka\0"
|
||||
"Asia/Dili\0"
|
||||
"Asia/Dubai\0"
|
||||
"Asia/Dushanbe\0"
|
||||
"Asia/Famagusta\0"
|
||||
"Asia/Gaza\0"
|
||||
"Asia/Hebron\0"
|
||||
"Asia/Ho_Chi_Minh\0"
|
||||
"Asia/Hong_Kong\0"
|
||||
"Asia/Hovd\0"
|
||||
"Asia/Irkutsk\0"
|
||||
"Asia/Jakarta\0"
|
||||
"Asia/Jayapura\0"
|
||||
"Asia/Jerusalem\0"
|
||||
"Asia/Kabul\0"
|
||||
"Asia/Kamchatka\0"
|
||||
"Asia/Karachi\0"
|
||||
"Asia/Kathmandu\0"
|
||||
"Asia/Khandyga\0"
|
||||
"Asia/Kolkata\0"
|
||||
"Asia/Krasnoyarsk\0"
|
||||
"Asia/Kuala_Lumpur\0"
|
||||
"Asia/Kuching\0"
|
||||
"Asia/Kuwait\0"
|
||||
"Asia/Macau\0"
|
||||
"Asia/Magadan\0"
|
||||
"Asia/Makassar\0"
|
||||
"Asia/Manila\0"
|
||||
"Asia/Muscat\0"
|
||||
"Asia/Nicosia\0"
|
||||
"Asia/Novokuznetsk\0"
|
||||
"Asia/Novosibirsk\0"
|
||||
"Asia/Omsk\0"
|
||||
"Asia/Oral\0"
|
||||
"Asia/Phnom_Penh\0"
|
||||
"Asia/Pontianak\0"
|
||||
"Asia/Pyongyang\0"
|
||||
"Asia/Qatar\0"
|
||||
"Asia/Qostanay\0"
|
||||
"Asia/Qyzylorda\0"
|
||||
"Asia/Riyadh\0"
|
||||
"Asia/Sakhalin\0"
|
||||
"Asia/Samarkand\0"
|
||||
"Asia/Seoul\0"
|
||||
"Asia/Shanghai\0"
|
||||
"Asia/Singapore\0"
|
||||
"Asia/Srednekolymsk\0"
|
||||
"Asia/Taipei\0"
|
||||
"Asia/Tashkent\0"
|
||||
"Asia/Tbilisi\0"
|
||||
"Asia/Tehran\0"
|
||||
"Asia/Thimphu\0"
|
||||
"Asia/Tokyo\0"
|
||||
"Asia/Tomsk\0"
|
||||
"Asia/Ulaanbaatar\0"
|
||||
"Asia/Urumqi\0"
|
||||
"Asia/Ust-Nera\0"
|
||||
"Asia/Vientiane\0"
|
||||
"Asia/Vladivostok\0"
|
||||
"Asia/Yakutsk\0"
|
||||
"Asia/Yangon\0"
|
||||
"Asia/Yekaterinburg\0"
|
||||
"Asia/Yerevan\0"
|
||||
"Atlantic/Azores\0"
|
||||
"Atlantic/Bermuda\0"
|
||||
"Atlantic/Canary\0"
|
||||
"Atlantic/Cape_Verde\0"
|
||||
"Atlantic/Faroe\0"
|
||||
"Atlantic/Madeira\0"
|
||||
"Atlantic/Reykjavik\0"
|
||||
"Atlantic/South_Georgia\0"
|
||||
"Atlantic/St_Helena\0"
|
||||
"Atlantic/Stanley\0"
|
||||
"Australia/Adelaide\0"
|
||||
"Australia/Brisbane\0"
|
||||
"Australia/Broken_Hill\0"
|
||||
"Australia/Currie\0"
|
||||
"Australia/Darwin\0"
|
||||
"Australia/Eucla\0"
|
||||
"Australia/Hobart\0"
|
||||
"Australia/Lindeman\0"
|
||||
"Australia/Lord_Howe\0"
|
||||
"Australia/Melbourne\0"
|
||||
"Australia/Perth\0"
|
||||
"Australia/Sydney\0"
|
||||
"Etc/UTC\0"
|
||||
"Europe/Amsterdam\0"
|
||||
"Europe/Andorra\0"
|
||||
"Europe/Astrakhan\0"
|
||||
"Europe/Athens\0"
|
||||
"Europe/Belgrade\0"
|
||||
"Europe/Berlin\0"
|
||||
"Europe/Bratislava\0"
|
||||
"Europe/Brussels\0"
|
||||
"Europe/Bucharest\0"
|
||||
"Europe/Budapest\0"
|
||||
"Europe/Busingen\0"
|
||||
"Europe/Chisinau\0"
|
||||
"Europe/Copenhagen\0"
|
||||
"Europe/Dublin\0"
|
||||
"Europe/Gibraltar\0"
|
||||
"Europe/Guernsey\0"
|
||||
"Europe/Helsinki\0"
|
||||
"Europe/Isle_of_Man\0"
|
||||
"Europe/Istanbul\0"
|
||||
"Europe/Jersey\0"
|
||||
"Europe/Kaliningrad\0"
|
||||
"Europe/Kiev\0"
|
||||
"Europe/Kirov\0"
|
||||
"Europe/Lisbon\0"
|
||||
"Europe/Ljubljana\0"
|
||||
"Europe/London\0"
|
||||
"Europe/Luxembourg\0"
|
||||
"Europe/Madrid\0"
|
||||
"Europe/Malta\0"
|
||||
"Europe/Mariehamn\0"
|
||||
"Europe/Minsk\0"
|
||||
"Europe/Monaco\0"
|
||||
"Europe/Moscow\0"
|
||||
"Europe/Oslo\0"
|
||||
"Europe/Paris\0"
|
||||
"Europe/Podgorica\0"
|
||||
"Europe/Prague\0"
|
||||
"Europe/Riga\0"
|
||||
"Europe/Rome\0"
|
||||
"Europe/Samara\0"
|
||||
"Europe/San_Marino\0"
|
||||
"Europe/Sarajevo\0"
|
||||
"Europe/Saratov\0"
|
||||
"Europe/Simferopol\0"
|
||||
"Europe/Skopje\0"
|
||||
"Europe/Sofia\0"
|
||||
"Europe/Stockholm\0"
|
||||
"Europe/Tallinn\0"
|
||||
"Europe/Tirane\0"
|
||||
"Europe/Ulyanovsk\0"
|
||||
"Europe/Uzhgorod\0"
|
||||
"Europe/Vaduz\0"
|
||||
"Europe/Vatican\0"
|
||||
"Europe/Vienna\0"
|
||||
"Europe/Vilnius\0"
|
||||
"Europe/Volgograd\0"
|
||||
"Europe/Warsaw\0"
|
||||
"Europe/Zagreb\0"
|
||||
"Europe/Zaporozhye\0"
|
||||
"Europe/Zurich\0"
|
||||
"Indian/Antananarivo\0"
|
||||
"Indian/Chagos\0"
|
||||
"Indian/Christmas\0"
|
||||
"Indian/Cocos\0"
|
||||
"Indian/Comoro\0"
|
||||
"Indian/Kerguelen\0"
|
||||
"Indian/Mahe\0"
|
||||
"Indian/Maldives\0"
|
||||
"Indian/Mauritius\0"
|
||||
"Indian/Mayotte\0"
|
||||
"Indian/Reunion\0"
|
||||
"Pacific/Apia\0"
|
||||
"Pacific/Auckland\0"
|
||||
"Pacific/Bougainville\0"
|
||||
"Pacific/Chatham\0"
|
||||
"Pacific/Chuuk\0"
|
||||
"Pacific/Easter\0"
|
||||
"Pacific/Efate\0"
|
||||
"Pacific/Enderbury\0"
|
||||
"Pacific/Fakaofo\0"
|
||||
"Pacific/Fiji\0"
|
||||
"Pacific/Funafuti\0"
|
||||
"Pacific/Galapagos\0"
|
||||
"Pacific/Gambier\0"
|
||||
"Pacific/Guadalcanal\0"
|
||||
"Pacific/Guam\0"
|
||||
"Pacific/Honolulu\0"
|
||||
"Pacific/Kiritimati\0"
|
||||
"Pacific/Kosrae\0"
|
||||
"Pacific/Kwajalein\0"
|
||||
"Pacific/Majuro\0"
|
||||
"Pacific/Marquesas\0"
|
||||
"Pacific/Midway\0"
|
||||
"Pacific/Nauru\0"
|
||||
"Pacific/Niue\0"
|
||||
"Pacific/Norfolk\0"
|
||||
"Pacific/Noumea\0"
|
||||
"Pacific/Pago_Pago\0"
|
||||
"Pacific/Palau\0"
|
||||
"Pacific/Pitcairn\0"
|
||||
"Pacific/Pohnpei\0"
|
||||
"Pacific/Port_Moresby\0"
|
||||
"Pacific/Rarotonga\0"
|
||||
"Pacific/Saipan\0"
|
||||
"Pacific/Tahiti\0"
|
||||
"Pacific/Tarawa\0"
|
||||
"Pacific/Tongatapu\0"
|
||||
"Pacific/Wake\0"
|
||||
"Pacific/Wallis\0";
|
||||
@@ -0,0 +1,443 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: ODbL-1.0
|
||||
* SPDX-FileCopyrightText: OpenStreetMap contributors
|
||||
*
|
||||
* Autogenerated using QGIS - do not edit!
|
||||
*/
|
||||
|
||||
#ifndef TIMEZONE_NAMES_P_H
|
||||
#define TIMEZONE_NAMES_P_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
enum Tz : uint16_t {
|
||||
Africa_Abidjan = 0,
|
||||
Africa_Accra = 15,
|
||||
Africa_Addis_Ababa = 28,
|
||||
Africa_Algiers = 47,
|
||||
Africa_Asmara = 62,
|
||||
Africa_Bamako = 76,
|
||||
Africa_Bangui = 90,
|
||||
Africa_Banjul = 104,
|
||||
Africa_Bissau = 118,
|
||||
Africa_Blantyre = 132,
|
||||
Africa_Brazzaville = 148,
|
||||
Africa_Bujumbura = 167,
|
||||
Africa_Cairo = 184,
|
||||
Africa_Casablanca = 197,
|
||||
Africa_Ceuta = 215,
|
||||
Africa_Conakry = 228,
|
||||
Africa_Dakar = 243,
|
||||
Africa_Dar_es_Salaam = 256,
|
||||
Africa_Djibouti = 277,
|
||||
Africa_Douala = 293,
|
||||
Africa_El_Aaiun = 307,
|
||||
Africa_Freetown = 323,
|
||||
Africa_Gaborone = 339,
|
||||
Africa_Harare = 355,
|
||||
Africa_Johannesburg = 369,
|
||||
Africa_Juba = 389,
|
||||
Africa_Kampala = 401,
|
||||
Africa_Khartoum = 416,
|
||||
Africa_Kigali = 432,
|
||||
Africa_Kinshasa = 446,
|
||||
Africa_Lagos = 462,
|
||||
Africa_Libreville = 475,
|
||||
Africa_Lome = 493,
|
||||
Africa_Luanda = 505,
|
||||
Africa_Lubumbashi = 519,
|
||||
Africa_Lusaka = 537,
|
||||
Africa_Malabo = 551,
|
||||
Africa_Maputo = 565,
|
||||
Africa_Maseru = 579,
|
||||
Africa_Mbabane = 593,
|
||||
Africa_Mogadishu = 608,
|
||||
Africa_Monrovia = 625,
|
||||
Africa_Nairobi = 641,
|
||||
Africa_Ndjamena = 656,
|
||||
Africa_Niamey = 672,
|
||||
Africa_Nouakchott = 686,
|
||||
Africa_Ouagadougou = 704,
|
||||
Africa_Porto_Novo = 723,
|
||||
Africa_Sao_Tome = 741,
|
||||
Africa_Tripoli = 757,
|
||||
Africa_Tunis = 772,
|
||||
Africa_Windhoek = 785,
|
||||
America_Adak = 801,
|
||||
America_Anchorage = 814,
|
||||
America_Anguilla = 832,
|
||||
America_Antigua = 849,
|
||||
America_Araguaina = 865,
|
||||
America_Argentina_Buenos_Aires = 883,
|
||||
America_Argentina_Catamarca = 914,
|
||||
America_Argentina_Cordoba = 942,
|
||||
America_Argentina_Jujuy = 968,
|
||||
America_Argentina_La_Rioja = 992,
|
||||
America_Argentina_Mendoza = 1019,
|
||||
America_Argentina_Rio_Gallegos = 1045,
|
||||
America_Argentina_Salta = 1076,
|
||||
America_Argentina_San_Juan = 1100,
|
||||
America_Argentina_San_Luis = 1127,
|
||||
America_Argentina_Tucuman = 1154,
|
||||
America_Argentina_Ushuaia = 1180,
|
||||
America_Aruba = 1206,
|
||||
America_Asuncion = 1220,
|
||||
America_Atikokan = 1237,
|
||||
America_Bahia = 1254,
|
||||
America_Bahia_Banderas = 1268,
|
||||
America_Barbados = 1291,
|
||||
America_Belem = 1308,
|
||||
America_Belize = 1322,
|
||||
America_Blanc_Sablon = 1337,
|
||||
America_Boa_Vista = 1358,
|
||||
America_Bogota = 1376,
|
||||
America_Boise = 1391,
|
||||
America_Cambridge_Bay = 1405,
|
||||
America_Campo_Grande = 1427,
|
||||
America_Cancun = 1448,
|
||||
America_Caracas = 1463,
|
||||
America_Cayenne = 1479,
|
||||
America_Cayman = 1495,
|
||||
America_Chicago = 1510,
|
||||
America_Chihuahua = 1526,
|
||||
America_Costa_Rica = 1544,
|
||||
America_Creston = 1563,
|
||||
America_Cuiaba = 1579,
|
||||
America_Curacao = 1594,
|
||||
America_Danmarkshavn = 1610,
|
||||
America_Dawson = 1631,
|
||||
America_Dawson_Creek = 1646,
|
||||
America_Denver = 1667,
|
||||
America_Detroit = 1682,
|
||||
America_Dominica = 1698,
|
||||
America_Edmonton = 1715,
|
||||
America_Eirunepe = 1732,
|
||||
America_El_Salvador = 1749,
|
||||
America_Fort_Nelson = 1769,
|
||||
America_Fortaleza = 1789,
|
||||
America_Glace_Bay = 1807,
|
||||
America_Goose_Bay = 1825,
|
||||
America_Grand_Turk = 1843,
|
||||
America_Grenada = 1862,
|
||||
America_Guadeloupe = 1878,
|
||||
America_Guatemala = 1897,
|
||||
America_Guayaquil = 1915,
|
||||
America_Guyana = 1933,
|
||||
America_Halifax = 1948,
|
||||
America_Havana = 1964,
|
||||
America_Hermosillo = 1979,
|
||||
America_Indiana_Indianapolis = 1998,
|
||||
America_Indiana_Knox = 2027,
|
||||
America_Indiana_Marengo = 2048,
|
||||
America_Indiana_Petersburg = 2072,
|
||||
America_Indiana_Tell_City = 2099,
|
||||
America_Indiana_Vevay = 2125,
|
||||
America_Indiana_Vincennes = 2147,
|
||||
America_Indiana_Winamac = 2173,
|
||||
America_Inuvik = 2197,
|
||||
America_Iqaluit = 2212,
|
||||
America_Jamaica = 2228,
|
||||
America_Juneau = 2244,
|
||||
America_Kentucky_Louisville = 2259,
|
||||
America_Kentucky_Monticello = 2287,
|
||||
America_Kralendijk = 2315,
|
||||
America_La_Paz = 2334,
|
||||
America_Lima = 2349,
|
||||
America_Los_Angeles = 2362,
|
||||
America_Lower_Princes = 2382,
|
||||
America_Maceio = 2404,
|
||||
America_Managua = 2419,
|
||||
America_Manaus = 2435,
|
||||
America_Marigot = 2450,
|
||||
America_Martinique = 2466,
|
||||
America_Matamoros = 2485,
|
||||
America_Mazatlan = 2503,
|
||||
America_Menominee = 2520,
|
||||
America_Merida = 2538,
|
||||
America_Metlakatla = 2553,
|
||||
America_Mexico_City = 2572,
|
||||
America_Miquelon = 2592,
|
||||
America_Moncton = 2609,
|
||||
America_Monterrey = 2625,
|
||||
America_Montevideo = 2643,
|
||||
America_Montserrat = 2662,
|
||||
America_Nassau = 2681,
|
||||
America_New_York = 2696,
|
||||
America_Nipigon = 2713,
|
||||
America_Nome = 2729,
|
||||
America_Noronha = 2742,
|
||||
America_North_Dakota_Beulah = 2758,
|
||||
America_North_Dakota_Center = 2786,
|
||||
America_North_Dakota_New_Salem = 2814,
|
||||
America_Nuuk = 2845,
|
||||
America_Ojinaga = 2858,
|
||||
America_Panama = 2874,
|
||||
America_Pangnirtung = 2889,
|
||||
America_Paramaribo = 2909,
|
||||
America_Phoenix = 2928,
|
||||
America_Port_au_Prince = 2944,
|
||||
America_Port_of_Spain = 2967,
|
||||
America_Porto_Velho = 2989,
|
||||
America_Puerto_Rico = 3009,
|
||||
America_Punta_Arenas = 3029,
|
||||
America_Rainy_River = 3050,
|
||||
America_Rankin_Inlet = 3070,
|
||||
America_Recife = 3091,
|
||||
America_Regina = 3106,
|
||||
America_Resolute = 3121,
|
||||
America_Rio_Branco = 3138,
|
||||
America_Santarem = 3157,
|
||||
America_Santiago = 3174,
|
||||
America_Santo_Domingo = 3191,
|
||||
America_Sao_Paulo = 3213,
|
||||
America_Scoresbysund = 3231,
|
||||
America_Sitka = 3252,
|
||||
America_St_Barthelemy = 3266,
|
||||
America_St_Johns = 3288,
|
||||
America_St_Kitts = 3305,
|
||||
America_St_Lucia = 3322,
|
||||
America_St_Thomas = 3339,
|
||||
America_St_Vincent = 3357,
|
||||
America_Swift_Current = 3376,
|
||||
America_Tegucigalpa = 3398,
|
||||
America_Thule = 3418,
|
||||
America_Thunder_Bay = 3432,
|
||||
America_Tijuana = 3452,
|
||||
America_Toronto = 3468,
|
||||
America_Tortola = 3484,
|
||||
America_Vancouver = 3500,
|
||||
America_Whitehorse = 3518,
|
||||
America_Winnipeg = 3537,
|
||||
America_Yakutat = 3554,
|
||||
America_Yellowknife = 3570,
|
||||
Antarctica_Casey = 3590,
|
||||
Antarctica_Davis = 3607,
|
||||
Antarctica_DumontDUrville = 3624,
|
||||
Antarctica_Macquarie = 3650,
|
||||
Antarctica_Mawson = 3671,
|
||||
Antarctica_McMurdo = 3689,
|
||||
Antarctica_Palmer = 3708,
|
||||
Antarctica_Rothera = 3726,
|
||||
Antarctica_Syowa = 3745,
|
||||
Antarctica_Troll = 3762,
|
||||
Antarctica_Vostok = 3779,
|
||||
Arctic_Longyearbyen = 3797,
|
||||
Asia_Aden = 3817,
|
||||
Asia_Almaty = 3827,
|
||||
Asia_Amman = 3839,
|
||||
Asia_Anadyr = 3850,
|
||||
Asia_Aqtau = 3862,
|
||||
Asia_Aqtobe = 3873,
|
||||
Asia_Ashgabat = 3885,
|
||||
Asia_Atyrau = 3899,
|
||||
Asia_Baghdad = 3911,
|
||||
Asia_Bahrain = 3924,
|
||||
Asia_Baku = 3937,
|
||||
Asia_Bangkok = 3947,
|
||||
Asia_Barnaul = 3960,
|
||||
Asia_Beirut = 3973,
|
||||
Asia_Bishkek = 3985,
|
||||
Asia_Brunei = 3998,
|
||||
Asia_Chita = 4010,
|
||||
Asia_Choibalsan = 4021,
|
||||
Asia_Colombo = 4037,
|
||||
Asia_Damascus = 4050,
|
||||
Asia_Dhaka = 4064,
|
||||
Asia_Dili = 4075,
|
||||
Asia_Dubai = 4085,
|
||||
Asia_Dushanbe = 4096,
|
||||
Asia_Famagusta = 4110,
|
||||
Asia_Gaza = 4125,
|
||||
Asia_Hebron = 4135,
|
||||
Asia_Ho_Chi_Minh = 4147,
|
||||
Asia_Hong_Kong = 4164,
|
||||
Asia_Hovd = 4179,
|
||||
Asia_Irkutsk = 4189,
|
||||
Asia_Jakarta = 4202,
|
||||
Asia_Jayapura = 4215,
|
||||
Asia_Jerusalem = 4229,
|
||||
Asia_Kabul = 4244,
|
||||
Asia_Kamchatka = 4255,
|
||||
Asia_Karachi = 4270,
|
||||
Asia_Kathmandu = 4283,
|
||||
Asia_Khandyga = 4298,
|
||||
Asia_Kolkata = 4312,
|
||||
Asia_Krasnoyarsk = 4325,
|
||||
Asia_Kuala_Lumpur = 4342,
|
||||
Asia_Kuching = 4360,
|
||||
Asia_Kuwait = 4373,
|
||||
Asia_Macau = 4385,
|
||||
Asia_Magadan = 4396,
|
||||
Asia_Makassar = 4409,
|
||||
Asia_Manila = 4423,
|
||||
Asia_Muscat = 4435,
|
||||
Asia_Nicosia = 4447,
|
||||
Asia_Novokuznetsk = 4460,
|
||||
Asia_Novosibirsk = 4478,
|
||||
Asia_Omsk = 4495,
|
||||
Asia_Oral = 4505,
|
||||
Asia_Phnom_Penh = 4515,
|
||||
Asia_Pontianak = 4531,
|
||||
Asia_Pyongyang = 4546,
|
||||
Asia_Qatar = 4561,
|
||||
Asia_Qostanay = 4572,
|
||||
Asia_Qyzylorda = 4586,
|
||||
Asia_Riyadh = 4601,
|
||||
Asia_Sakhalin = 4613,
|
||||
Asia_Samarkand = 4627,
|
||||
Asia_Seoul = 4642,
|
||||
Asia_Shanghai = 4653,
|
||||
Asia_Singapore = 4667,
|
||||
Asia_Srednekolymsk = 4682,
|
||||
Asia_Taipei = 4701,
|
||||
Asia_Tashkent = 4713,
|
||||
Asia_Tbilisi = 4727,
|
||||
Asia_Tehran = 4740,
|
||||
Asia_Thimphu = 4752,
|
||||
Asia_Tokyo = 4765,
|
||||
Asia_Tomsk = 4776,
|
||||
Asia_Ulaanbaatar = 4787,
|
||||
Asia_Urumqi = 4804,
|
||||
Asia_Ust_Nera = 4816,
|
||||
Asia_Vientiane = 4830,
|
||||
Asia_Vladivostok = 4845,
|
||||
Asia_Yakutsk = 4862,
|
||||
Asia_Yangon = 4875,
|
||||
Asia_Yekaterinburg = 4887,
|
||||
Asia_Yerevan = 4906,
|
||||
Atlantic_Azores = 4919,
|
||||
Atlantic_Bermuda = 4935,
|
||||
Atlantic_Canary = 4952,
|
||||
Atlantic_Cape_Verde = 4968,
|
||||
Atlantic_Faroe = 4988,
|
||||
Atlantic_Madeira = 5003,
|
||||
Atlantic_Reykjavik = 5020,
|
||||
Atlantic_South_Georgia = 5039,
|
||||
Atlantic_St_Helena = 5062,
|
||||
Atlantic_Stanley = 5081,
|
||||
Australia_Adelaide = 5098,
|
||||
Australia_Brisbane = 5117,
|
||||
Australia_Broken_Hill = 5136,
|
||||
Australia_Currie = 5158,
|
||||
Australia_Darwin = 5175,
|
||||
Australia_Eucla = 5192,
|
||||
Australia_Hobart = 5208,
|
||||
Australia_Lindeman = 5225,
|
||||
Australia_Lord_Howe = 5244,
|
||||
Australia_Melbourne = 5264,
|
||||
Australia_Perth = 5284,
|
||||
Australia_Sydney = 5300,
|
||||
Etc_UTC = 5317,
|
||||
Europe_Amsterdam = 5325,
|
||||
Europe_Andorra = 5342,
|
||||
Europe_Astrakhan = 5357,
|
||||
Europe_Athens = 5374,
|
||||
Europe_Belgrade = 5388,
|
||||
Europe_Berlin = 5404,
|
||||
Europe_Bratislava = 5418,
|
||||
Europe_Brussels = 5436,
|
||||
Europe_Bucharest = 5452,
|
||||
Europe_Budapest = 5469,
|
||||
Europe_Busingen = 5485,
|
||||
Europe_Chisinau = 5501,
|
||||
Europe_Copenhagen = 5517,
|
||||
Europe_Dublin = 5535,
|
||||
Europe_Gibraltar = 5549,
|
||||
Europe_Guernsey = 5566,
|
||||
Europe_Helsinki = 5582,
|
||||
Europe_Isle_of_Man = 5598,
|
||||
Europe_Istanbul = 5617,
|
||||
Europe_Jersey = 5633,
|
||||
Europe_Kaliningrad = 5647,
|
||||
Europe_Kiev = 5666,
|
||||
Europe_Kirov = 5678,
|
||||
Europe_Lisbon = 5691,
|
||||
Europe_Ljubljana = 5705,
|
||||
Europe_London = 5722,
|
||||
Europe_Luxembourg = 5736,
|
||||
Europe_Madrid = 5754,
|
||||
Europe_Malta = 5768,
|
||||
Europe_Mariehamn = 5781,
|
||||
Europe_Minsk = 5798,
|
||||
Europe_Monaco = 5811,
|
||||
Europe_Moscow = 5825,
|
||||
Europe_Oslo = 5839,
|
||||
Europe_Paris = 5851,
|
||||
Europe_Podgorica = 5864,
|
||||
Europe_Prague = 5881,
|
||||
Europe_Riga = 5895,
|
||||
Europe_Rome = 5907,
|
||||
Europe_Samara = 5919,
|
||||
Europe_San_Marino = 5933,
|
||||
Europe_Sarajevo = 5951,
|
||||
Europe_Saratov = 5967,
|
||||
Europe_Simferopol = 5982,
|
||||
Europe_Skopje = 6000,
|
||||
Europe_Sofia = 6014,
|
||||
Europe_Stockholm = 6027,
|
||||
Europe_Tallinn = 6044,
|
||||
Europe_Tirane = 6059,
|
||||
Europe_Ulyanovsk = 6073,
|
||||
Europe_Uzhgorod = 6090,
|
||||
Europe_Vaduz = 6106,
|
||||
Europe_Vatican = 6119,
|
||||
Europe_Vienna = 6134,
|
||||
Europe_Vilnius = 6148,
|
||||
Europe_Volgograd = 6163,
|
||||
Europe_Warsaw = 6180,
|
||||
Europe_Zagreb = 6194,
|
||||
Europe_Zaporozhye = 6208,
|
||||
Europe_Zurich = 6226,
|
||||
Indian_Antananarivo = 6240,
|
||||
Indian_Chagos = 6260,
|
||||
Indian_Christmas = 6274,
|
||||
Indian_Cocos = 6291,
|
||||
Indian_Comoro = 6304,
|
||||
Indian_Kerguelen = 6318,
|
||||
Indian_Mahe = 6335,
|
||||
Indian_Maldives = 6347,
|
||||
Indian_Mauritius = 6363,
|
||||
Indian_Mayotte = 6380,
|
||||
Indian_Reunion = 6395,
|
||||
Pacific_Apia = 6410,
|
||||
Pacific_Auckland = 6423,
|
||||
Pacific_Bougainville = 6440,
|
||||
Pacific_Chatham = 6461,
|
||||
Pacific_Chuuk = 6477,
|
||||
Pacific_Easter = 6491,
|
||||
Pacific_Efate = 6506,
|
||||
Pacific_Enderbury = 6520,
|
||||
Pacific_Fakaofo = 6538,
|
||||
Pacific_Fiji = 6554,
|
||||
Pacific_Funafuti = 6567,
|
||||
Pacific_Galapagos = 6584,
|
||||
Pacific_Gambier = 6602,
|
||||
Pacific_Guadalcanal = 6618,
|
||||
Pacific_Guam = 6638,
|
||||
Pacific_Honolulu = 6651,
|
||||
Pacific_Kiritimati = 6668,
|
||||
Pacific_Kosrae = 6687,
|
||||
Pacific_Kwajalein = 6702,
|
||||
Pacific_Majuro = 6720,
|
||||
Pacific_Marquesas = 6735,
|
||||
Pacific_Midway = 6753,
|
||||
Pacific_Nauru = 6768,
|
||||
Pacific_Niue = 6782,
|
||||
Pacific_Norfolk = 6795,
|
||||
Pacific_Noumea = 6811,
|
||||
Pacific_Pago_Pago = 6826,
|
||||
Pacific_Palau = 6844,
|
||||
Pacific_Pitcairn = 6858,
|
||||
Pacific_Pohnpei = 6875,
|
||||
Pacific_Port_Moresby = 6891,
|
||||
Pacific_Rarotonga = 6912,
|
||||
Pacific_Saipan = 6930,
|
||||
Pacific_Tahiti = 6945,
|
||||
Pacific_Tarawa = 6960,
|
||||
Pacific_Tongatapu = 6975,
|
||||
Pacific_Wake = 6993,
|
||||
Pacific_Wallis = 7006,
|
||||
Undefined = 7020,
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "isocodes_p.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
// "unit tests" for the low-level encoding functions
|
||||
static_assert(IsoCodes::mapToUpper(QLatin1Char('a')) == 'A');
|
||||
static_assert(IsoCodes::mapToAlphaNumKey(QLatin1Char('A')) == 11);
|
||||
static_assert(IsoCodes::mapToAlphaNumKey('A') == IsoCodes::mapToAlphaNumKey('a'));
|
||||
static_assert(IsoCodes::mapToAlphaNumKey(QLatin1Char('z')) < IsoCodes::AlphaNumKeyFactor);
|
||||
static_assert(IsoCodes::mapToAlphaNumKey(QLatin1Char('0')) == 1);
|
||||
static_assert(IsoCodes::mapToAlphaNumKey(QLatin1Char('9')) == 10);
|
||||
static_assert(IsoCodes::AlphaNumKeyFactor * IsoCodes::AlphaNumKeyFactor * IsoCodes::AlphaNumKeyFactor < std::numeric_limits<uint16_t>::max());
|
||||
|
||||
static_assert(IsoCodes::mapFromAlphaNumKey(IsoCodes::mapToAlphaNumKey('0')) == '0');
|
||||
static_assert(IsoCodes::mapFromAlphaNumKey(IsoCodes::mapToAlphaNumKey('9')) == '9');
|
||||
static_assert(IsoCodes::mapFromAlphaNumKey(IsoCodes::mapToAlphaNumKey('a')) == 'A');
|
||||
static_assert(IsoCodes::mapFromAlphaNumKey(IsoCodes::mapToAlphaNumKey('Z')) == 'Z');
|
||||
|
||||
static_assert(IsoCodes::alpha2CodeToKey("AZ") == 0x415a);
|
||||
static_assert(IsoCodes::alpha2CodeToKey("az") == 0x415a);
|
||||
static_assert(IsoCodes::alpha2CodeToKey("Az") == 0x415a);
|
||||
static_assert(IsoCodes::alpha2CodeToKey("ZA") == 0x5a41);
|
||||
static_assert(IsoCodes::alpha2CodeToKey("NZ") == IsoCodes::alpha2CodeToKey(u"NZ"));
|
||||
|
||||
static_assert(IsoCodes::alpha2CodeToKey("") == 0);
|
||||
static_assert(IsoCodes::alpha2CodeToKey("12") == 0);
|
||||
static_assert(IsoCodes::alpha2CodeToKey("A") == 0);
|
||||
static_assert(IsoCodes::alpha2CodeToKey("ABC") == 0);
|
||||
static_assert(IsoCodes::alpha2CodeToKey("A@") == 0);
|
||||
|
||||
static_assert(IsoCodes::alpha2CodeToKey("AA") < IsoCodes::alpha2CodeToKey("AB"));
|
||||
static_assert(IsoCodes::alpha2CodeToKey("AZ") < IsoCodes::alpha2CodeToKey("BA"));
|
||||
|
||||
static_assert(IsoCodes::alpha3CodeToKey("ZZZ") < std::numeric_limits<uint16_t>::max());
|
||||
static_assert(IsoCodes::alpha3CodeToKey("AAA") > 0);
|
||||
static_assert(IsoCodes::alpha3CodeToKey("AAA") < IsoCodes::alpha3CodeToKey("AAB"));
|
||||
static_assert(IsoCodes::alpha3CodeToKey("AAB") < IsoCodes::alpha3CodeToKey("BAA"));
|
||||
static_assert(IsoCodes::alpha3CodeToKey("NZL") == IsoCodes::alpha3CodeToKey(u"NZL"));
|
||||
|
||||
static_assert(IsoCodes::alpha3CodeToKey("") == 0);
|
||||
static_assert(IsoCodes::alpha3CodeToKey("AA") == 0);
|
||||
static_assert(IsoCodes::alpha3CodeToKey("ABCD") == 0);
|
||||
static_assert(IsoCodes::alpha3CodeToKey("AB1") == 0);
|
||||
static_assert(IsoCodes::alpha3CodeToKey("A@C") == 0);
|
||||
|
||||
static_assert(IsoCodes::subdivisionCodeToKey("AA-AAA") > 0);
|
||||
static_assert(IsoCodes::subdivisionCodeToKey("ZZ-ZZZ") > 0);
|
||||
static_assert(IsoCodes::subdivisionCodeToKey("ZZ-999") < std::numeric_limits<uint32_t>::max());
|
||||
static_assert(IsoCodes::subdivisionCodeToKey("AA-A") < IsoCodes::subdivisionCodeToKey("AA-AA"));
|
||||
static_assert(IsoCodes::subdivisionCodeToKey("AA-AAA") < IsoCodes::subdivisionCodeToKey("AA-AAB"));
|
||||
static_assert(IsoCodes::subdivisionCodeToKey("AA-AAA") < IsoCodes::subdivisionCodeToKey("AA-AB"));
|
||||
static_assert(IsoCodes::subdivisionCodeToKey("AA-AAB") < IsoCodes::subdivisionCodeToKey("AA-BAA"));
|
||||
static_assert(IsoCodes::subdivisionCodeToKey("AA-AA1") < IsoCodes::subdivisionCodeToKey("AA-AAZ"));
|
||||
static_assert(IsoCodes::subdivisionCodeToKey("FR-99") < IsoCodes::subdivisionCodeToKey("FR-RE"));
|
||||
static_assert(IsoCodes::subdivisionCodeToKey("AB-cd1") == IsoCodes::subdivisionCodeToKey("AB-CD1"));
|
||||
|
||||
static_assert(IsoCodes::subdivisionCodeToKey("") == 0);
|
||||
static_assert(IsoCodes::subdivisionCodeToKey("AA-") == 0);
|
||||
static_assert(IsoCodes::subdivisionCodeToKey("12-ABC") == 0);
|
||||
static_assert(IsoCodes::subdivisionCodeToKey("AA-@") == 0);
|
||||
static_assert(IsoCodes::subdivisionCodeToKey("AB") == 0);
|
||||
static_assert(IsoCodes::subdivisionCodeToKey("ABC") == 0);
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef ISOCODES_P_H
|
||||
#define ISOCODES_P_H
|
||||
|
||||
#include <QStringView>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
/**
|
||||
* Utilities for efficient storage of ISO codes.
|
||||
* The focus on constexpr here matters, as this is used for the compiled in data tables,
|
||||
* anything in there has to be constexpr in order to put the data tables into the shared read-only
|
||||
* data section.
|
||||
*
|
||||
* There's basically two formats in here:
|
||||
* - upper case + digit codes of up to 3 characters are stored as a 3 digit base 37 number, which
|
||||
* fits into a 16bit value
|
||||
* To simplify data table handling this is done in a way that lexicographical order is retained.
|
||||
* - two letter upper case codes like ISO 3166-1 alpha2: those are stored equivalent to a const char[2]
|
||||
* technically the same approach as for 3 char codes could be used as well, but that doesn't give us
|
||||
* any space advantage while considerably easing debugging (codes are directly readable).
|
||||
*/
|
||||
namespace IsoCodes
|
||||
{
|
||||
constexpr inline bool isAlpha(char c)
|
||||
{
|
||||
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
|
||||
}
|
||||
|
||||
constexpr inline bool isAlpha(QChar c)
|
||||
{
|
||||
return c.row() == 0 ? isAlpha(c.cell()) : false;
|
||||
}
|
||||
|
||||
constexpr inline bool isDigit(char c)
|
||||
{
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
constexpr inline bool isDigit(QChar c)
|
||||
{
|
||||
return c.row() == 0 ? isDigit(c.cell()) : false;
|
||||
}
|
||||
|
||||
constexpr inline uint8_t mapToUpper(char c)
|
||||
{
|
||||
return c >= 'a' ? c - 32 : c;
|
||||
}
|
||||
|
||||
constexpr inline uint8_t mapToUpper(QChar c)
|
||||
{
|
||||
return mapToUpper(c.cell());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr inline uint16_t alpha2CodeToKey(T code, std::size_t size)
|
||||
{
|
||||
return (size == 2 && isAlpha(code[0]) && isAlpha(code[1])) ? mapToUpper(code[0]) << 8 | mapToUpper(code[1]) : 0;
|
||||
}
|
||||
|
||||
template<std::size_t N>
|
||||
constexpr inline uint16_t alpha2CodeToKey(const char (&code)[N])
|
||||
{
|
||||
return alpha2CodeToKey(code, N - 1);
|
||||
}
|
||||
|
||||
constexpr inline uint16_t alpha2CodeToKey(QStringView code)
|
||||
{
|
||||
return alpha2CodeToKey(code, code.size());
|
||||
}
|
||||
|
||||
constexpr inline uint8_t mapToAlphaNumKey(char c)
|
||||
{
|
||||
// this maps digits 0-9 to values 1-10, and letters to the numbers 11-36
|
||||
uint8_t key = c;
|
||||
if (key <= '9') {
|
||||
return key - '/';
|
||||
} else if (key >= 'a') {
|
||||
key -= 32;
|
||||
}
|
||||
return key - 'A' + 11;
|
||||
}
|
||||
|
||||
constexpr inline uint8_t mapToAlphaNumKey(QChar c)
|
||||
{
|
||||
return mapToAlphaNumKey(c.cell());
|
||||
}
|
||||
|
||||
enum {
|
||||
AlphaNumKeyFactor = 37,
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
constexpr inline char mapFromAlphaNumKey(T key)
|
||||
{
|
||||
char c = key % IsoCodes::AlphaNumKeyFactor;
|
||||
if (c > 0 && c < 11) {
|
||||
return c + '/';
|
||||
}
|
||||
if (c >= 11) {
|
||||
return c + 'A' - 11;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr inline uint16_t alphaNum3CodeToKey(T code, std::size_t size)
|
||||
{
|
||||
if (size > 3 || size == 0) {
|
||||
return 0;
|
||||
}
|
||||
uint16_t key = 0;
|
||||
for (std::size_t i = 0; i < size; ++i) {
|
||||
if (!isAlpha(code[i]) && !isDigit(code[i])) {
|
||||
return 0;
|
||||
}
|
||||
key *= AlphaNumKeyFactor;
|
||||
key += mapToAlphaNumKey(code[i]);
|
||||
}
|
||||
for (std::size_t i = size; i < 3; ++i) { // "left align" to retain lexicographical order
|
||||
key *= AlphaNumKeyFactor;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
constexpr inline uint16_t alphaNum3CodeToKey(QStringView code)
|
||||
{
|
||||
return alphaNum3CodeToKey(code, code.size());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr inline uint16_t alpha3CodeToKey(T code, std::size_t size)
|
||||
{
|
||||
return (size == 3 && isAlpha(code[0]) && isAlpha(code[1]) && isAlpha(code[2])) ? alphaNum3CodeToKey(code, 3) : 0;
|
||||
}
|
||||
|
||||
template<std::size_t N>
|
||||
constexpr inline uint16_t alpha3CodeToKey(const char (&code)[N])
|
||||
{
|
||||
return alpha3CodeToKey(code, N - 1);
|
||||
}
|
||||
|
||||
constexpr inline uint16_t alpha3CodeToKey(QStringView code)
|
||||
{
|
||||
return alpha3CodeToKey(code, code.size());
|
||||
}
|
||||
|
||||
constexpr inline uint32_t subdivisionCodeToKey(const char *code, std::size_t size)
|
||||
{
|
||||
if (size < 4 || code[2] != '-') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto countryKey = alpha2CodeToKey(code, 2);
|
||||
const auto subdivKey = alphaNum3CodeToKey(code + 3, size - 3);
|
||||
return countryKey > 0 && subdivKey > 0 ? ((uint32_t)(countryKey) << 16 | subdivKey) : 0;
|
||||
}
|
||||
|
||||
constexpr inline uint32_t subdivisionCodeToKey(QStringView code)
|
||||
{
|
||||
if (code.size() < 4 || code[2] != QLatin1Char('-')) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto countryKey = alpha2CodeToKey(code.left(2));
|
||||
const auto subdivKey = alphaNum3CodeToKey(code.mid(3), code.size() - 3);
|
||||
return countryKey > 0 && subdivKey > 0 ? ((uint32_t)(countryKey) << 16 | subdivKey) : 0;
|
||||
}
|
||||
|
||||
template<std::size_t N>
|
||||
constexpr inline uint32_t subdivisionCodeToKey(const char (&code)[N])
|
||||
{
|
||||
return subdivisionCodeToKey(code, N - 1);
|
||||
}
|
||||
|
||||
/// Before v4.16 iso-codes used for parent code just the subdivision code, without the country
|
||||
/// (only by error sometimes). Since that version the full code now is always used.
|
||||
/// Handle both cases gracefully.
|
||||
/// Does not check the country part for sanity, but just discards the info.
|
||||
constexpr inline uint16_t parentCodeToKey(QStringView code)
|
||||
{
|
||||
if (code.size() < 4) {
|
||||
return alphaNum3CodeToKey(code);
|
||||
}
|
||||
if (code[2] != QLatin1Char('-')) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto countryKey = alpha2CodeToKey(code.left(2));
|
||||
const auto subdivKey = alphaNum3CodeToKey(code.mid(3), code.size() - 3);
|
||||
return countryKey > 0 ? subdivKey : 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ISOCODES_P_H
|
||||
@@ -0,0 +1,334 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "config-localedata.h"
|
||||
|
||||
#include "isocodes_p.h"
|
||||
#include "isocodescache_p.h"
|
||||
#include "logging.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QStandardPaths>
|
||||
|
||||
// increment those when changing the format
|
||||
enum : uint32_t {
|
||||
Iso3166_1CacheHeader = 0x4B493101,
|
||||
Iso3166_2CacheHeader = 0x4B493201,
|
||||
};
|
||||
|
||||
static QString isoCodesPath(QStringView file)
|
||||
{
|
||||
#ifndef Q_OS_ANDROID
|
||||
auto path = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String("iso-codes/json/") + file, QStandardPaths::LocateFile);
|
||||
if (!path.isEmpty()) {
|
||||
return path;
|
||||
}
|
||||
|
||||
// search manually in the compile-time determined prefix
|
||||
// needed for example for non-installed Windows binaries to work, such as unit tests
|
||||
for (const char *installLocation : {"/share", "/bin/data"}) {
|
||||
path = QLatin1String(ISO_CODES_PREFIX) + QLatin1String(installLocation) + QLatin1String("/iso-codes/json/") + file;
|
||||
if (QFileInfo::exists(path)) {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
#else
|
||||
return QLatin1String("assets:/share/iso-codes/json/") + file;
|
||||
#endif
|
||||
}
|
||||
|
||||
static QString cachePath()
|
||||
{
|
||||
return QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + QLatin1String("/org.kde.ki18n/iso-codes/");
|
||||
}
|
||||
|
||||
static QString cacheFilePath(QStringView file)
|
||||
{
|
||||
return cachePath() + file;
|
||||
}
|
||||
|
||||
IsoCodesCache::~IsoCodesCache() = default;
|
||||
|
||||
IsoCodesCache *IsoCodesCache::instance()
|
||||
{
|
||||
static IsoCodesCache s_cache;
|
||||
return &s_cache;
|
||||
}
|
||||
|
||||
void IsoCodesCache::loadIso3166_1()
|
||||
{
|
||||
if (!m_iso3166_1CacheData && !loadIso3166_1Cache()) {
|
||||
QDir().mkpath(cachePath());
|
||||
createIso3166_1Cache(isoCodesPath(u"iso_3166-1.json"), cacheFilePath(u"iso_3166-1"));
|
||||
loadIso3166_1Cache();
|
||||
}
|
||||
}
|
||||
|
||||
static std::unique_ptr<QFile> openCacheFile(QStringView cacheFileName, QStringView isoCodesFileName)
|
||||
{
|
||||
QFileInfo jsonFi(isoCodesPath(isoCodesFileName));
|
||||
if (!jsonFi.exists()) { // no source file means we can only use an embedded cache
|
||||
auto f = std::make_unique<QFile>(QLatin1String(":/org.kde.ki18n/iso-codes/cache/") + cacheFileName);
|
||||
if (!f->open(QFile::ReadOnly) || f->size() < 8) {
|
||||
return {};
|
||||
}
|
||||
return f;
|
||||
}
|
||||
auto f = std::make_unique<QFile>(cacheFilePath(cacheFileName));
|
||||
if (!f->open(QFile::ReadOnly) || f->fileTime(QFile::FileModificationTime) < jsonFi.lastModified() || f->size() < 8) {
|
||||
return {};
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
bool IsoCodesCache::loadIso3166_1Cache()
|
||||
{
|
||||
auto f = openCacheFile(u"iso_3166-1", u"iso_3166-1.json");
|
||||
if (!f) {
|
||||
return false;
|
||||
}
|
||||
m_iso3166_1CacheSize = f->size();
|
||||
|
||||
// validate cache file is usable
|
||||
// header matches
|
||||
const auto data = f->map(0, m_iso3166_1CacheSize);
|
||||
if (*reinterpret_cast<const uint32_t *>(data) != Iso3166_1CacheHeader) {
|
||||
return false;
|
||||
}
|
||||
// lookup tables fit into the available size
|
||||
const auto size = *(reinterpret_cast<const uint32_t *>(data) + 1);
|
||||
if (sizeof(Iso3166_1CacheHeader) + sizeof(size) + size * sizeof(MapEntry<uint16_t>) * 2 >= m_iso3166_1CacheSize) {
|
||||
return false;
|
||||
}
|
||||
// string table is 0 terminated
|
||||
if (data[m_iso3166_1CacheSize - 1] != '\0') {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_iso3166_1CacheFile = std::move(f);
|
||||
m_iso3166_1CacheData = data;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t IsoCodesCache::countryCount() const
|
||||
{
|
||||
return m_iso3166_1CacheData ? *(reinterpret_cast<const uint32_t *>(m_iso3166_1CacheData) + 1) : 0;
|
||||
}
|
||||
|
||||
const MapEntry<uint16_t> *IsoCodesCache::countryNameMapBegin() const
|
||||
{
|
||||
return m_iso3166_1CacheData ? reinterpret_cast<const MapEntry<uint16_t> *>(m_iso3166_1CacheData + sizeof(uint32_t) * 2) : nullptr;
|
||||
}
|
||||
|
||||
const MapEntry<uint16_t> *IsoCodesCache::countryAlpha3MapBegin() const
|
||||
{
|
||||
return m_iso3166_1CacheData ? countryNameMapBegin() + countryCount() : nullptr;
|
||||
}
|
||||
|
||||
const char *IsoCodesCache::countryStringTableLookup(uint16_t offset) const
|
||||
{
|
||||
if (m_iso3166_1CacheData) {
|
||||
const auto pos = offset + 2 * sizeof(uint32_t) + 2 * countryCount() * sizeof(MapEntry<uint16_t>);
|
||||
return m_iso3166_1CacheSize > pos ? reinterpret_cast<const char *>(m_iso3166_1CacheData + pos) : nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void IsoCodesCache::createIso3166_1Cache(const QString &isoCodesPath, const QString &cacheFilePath)
|
||||
{
|
||||
qCDebug(KI18NLD) << "Rebuilding ISO 3166-1 cache";
|
||||
|
||||
QFile file(isoCodesPath);
|
||||
if (!file.open(QFile::ReadOnly)) {
|
||||
qCWarning(KI18NLD) << "Unable to open iso_3166-1.json" << isoCodesPath << file.errorString();
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<MapEntry<uint16_t>> alpha2NameMap;
|
||||
std::vector<MapEntry<uint16_t>> alpha3alpha2Map;
|
||||
QByteArray iso3166_1stringTable;
|
||||
|
||||
const auto doc = QJsonDocument::fromJson(file.readAll());
|
||||
const auto array = doc.object().value(QLatin1String("3166-1")).toArray();
|
||||
for (const auto &entryVal : array) {
|
||||
const auto entry = entryVal.toObject();
|
||||
const auto alpha2 = entry.value(QLatin1String("alpha_2")).toString();
|
||||
if (alpha2.size() != 2) {
|
||||
continue;
|
||||
}
|
||||
const auto alpha2Key = IsoCodes::alpha2CodeToKey(alpha2);
|
||||
|
||||
assert(std::numeric_limits<uint16_t>::max() > iso3166_1stringTable.size());
|
||||
alpha2NameMap.push_back({alpha2Key, (uint16_t)iso3166_1stringTable.size()});
|
||||
iso3166_1stringTable.append(entry.value(QLatin1String("name")).toString().toUtf8());
|
||||
iso3166_1stringTable.append('\0');
|
||||
|
||||
const auto alpha3Key = IsoCodes::alpha3CodeToKey(entry.value(QLatin1String("alpha_3")).toString());
|
||||
alpha3alpha2Map.push_back({alpha3Key, alpha2Key});
|
||||
}
|
||||
|
||||
std::sort(alpha2NameMap.begin(), alpha2NameMap.end());
|
||||
std::sort(alpha3alpha2Map.begin(), alpha3alpha2Map.end());
|
||||
|
||||
// write out binary cache file
|
||||
QFile cache(cacheFilePath);
|
||||
if (!cache.open(QFile::WriteOnly)) {
|
||||
qCWarning(KI18NLD) << "Failed to write ISO 3166-1 cache:" << cache.errorString() << cache.fileName();
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t n = Iso3166_1CacheHeader;
|
||||
cache.write(reinterpret_cast<const char *>(&n), 4); // header
|
||||
n = alpha2NameMap.size();
|
||||
cache.write(reinterpret_cast<const char *>(&n), 4); // size
|
||||
for (auto entry : alpha2NameMap) {
|
||||
cache.write(reinterpret_cast<const char *>(&entry), sizeof(entry));
|
||||
}
|
||||
for (auto entry : alpha3alpha2Map) {
|
||||
cache.write(reinterpret_cast<const char *>(&entry), sizeof(entry));
|
||||
}
|
||||
cache.write(iso3166_1stringTable);
|
||||
}
|
||||
|
||||
void IsoCodesCache::loadIso3166_2()
|
||||
{
|
||||
if (!m_iso3166_2CacheData && !loadIso3166_2Cache()) {
|
||||
QDir().mkpath(cachePath());
|
||||
createIso3166_2Cache(isoCodesPath(u"iso_3166-2.json"), cacheFilePath(u"iso_3166-2"));
|
||||
loadIso3166_2Cache();
|
||||
}
|
||||
}
|
||||
|
||||
bool IsoCodesCache::loadIso3166_2Cache()
|
||||
{
|
||||
auto f = openCacheFile(u"iso_3166-2", u"iso_3166-2.json");
|
||||
if (!f) {
|
||||
return false;
|
||||
}
|
||||
m_iso3166_2CacheSize = f->size();
|
||||
|
||||
// validate cache file is usable
|
||||
// header matches
|
||||
const auto data = f->map(0, m_iso3166_2CacheSize);
|
||||
if (*reinterpret_cast<const uint32_t *>(data) != Iso3166_2CacheHeader) {
|
||||
return false;
|
||||
}
|
||||
// name lookup table fits into the available size
|
||||
auto size = *(reinterpret_cast<const uint32_t *>(data) + 1);
|
||||
auto offset = 3 * sizeof(uint32_t) + size * sizeof(MapEntry<uint32_t>);
|
||||
if (offset >= m_iso3166_2CacheSize) {
|
||||
return false;
|
||||
}
|
||||
// hierarchy map boundary check
|
||||
size = *(reinterpret_cast<const uint32_t *>(data + offset) - 1);
|
||||
offset += size * sizeof(MapEntry<uint32_t>);
|
||||
if (offset >= m_iso3166_2CacheSize) {
|
||||
return false;
|
||||
}
|
||||
// string table is 0 terminated
|
||||
if (data[m_iso3166_2CacheSize - 1] != '\0') {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_iso3166_2CacheFile = std::move(f);
|
||||
m_iso3166_2CacheData = data;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t IsoCodesCache::subdivisionCount() const
|
||||
{
|
||||
return m_iso3166_2CacheData ? *(reinterpret_cast<const uint32_t *>(m_iso3166_2CacheData) + 1) : 0;
|
||||
}
|
||||
|
||||
const MapEntry<uint32_t> *IsoCodesCache::subdivisionNameMapBegin() const
|
||||
{
|
||||
return m_iso3166_2CacheData ? reinterpret_cast<const MapEntry<uint32_t> *>(m_iso3166_2CacheData + 2 * sizeof(uint32_t)) : nullptr;
|
||||
}
|
||||
|
||||
uint32_t IsoCodesCache::subdivisionHierachyMapSize() const
|
||||
{
|
||||
return m_iso3166_2CacheData
|
||||
? *(reinterpret_cast<const uint32_t *>(m_iso3166_2CacheData + 2 * sizeof(uint32_t) + subdivisionCount() * sizeof(MapEntry<uint32_t>)))
|
||||
: 0;
|
||||
}
|
||||
|
||||
const MapEntry<uint32_t> *IsoCodesCache::subdivisionParentMapBegin() const
|
||||
{
|
||||
return m_iso3166_2CacheData
|
||||
? reinterpret_cast<const MapEntry<uint32_t> *>(m_iso3166_2CacheData + 3 * sizeof(uint32_t) + subdivisionCount() * sizeof(MapEntry<uint32_t>))
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
const char *IsoCodesCache::subdivisionStringTableLookup(uint16_t offset) const
|
||||
{
|
||||
if (m_iso3166_2CacheData) {
|
||||
const auto pos = offset + 3 * sizeof(uint32_t) + (subdivisionCount() + subdivisionHierachyMapSize()) * sizeof(MapEntry<uint32_t>);
|
||||
return m_iso3166_2CacheSize > pos ? reinterpret_cast<const char *>(m_iso3166_2CacheData + pos) : nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void IsoCodesCache::createIso3166_2Cache(const QString &isoCodesPath, const QString &cacheFilePath)
|
||||
{
|
||||
qCDebug(KI18NLD) << "Rebuilding ISO 3166-2 cache";
|
||||
QFile file(isoCodesPath);
|
||||
if (!file.open(QFile::ReadOnly)) {
|
||||
qCWarning(KI18NLD) << "Unable to open iso_3166-2.json" << isoCodesPath << file.errorString();
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<MapEntry<uint32_t>> subdivNameMap;
|
||||
std::vector<MapEntry<uint32_t>> subdivParentMap;
|
||||
QByteArray iso3166_2stringTable;
|
||||
|
||||
const auto doc = QJsonDocument::fromJson(file.readAll());
|
||||
const auto array = doc.object().value(QLatin1String("3166-2")).toArray();
|
||||
for (const auto &entryVal : array) {
|
||||
const auto entry = entryVal.toObject();
|
||||
const auto key = IsoCodes::subdivisionCodeToKey(entry.value(QLatin1String("code")).toString());
|
||||
|
||||
assert(std::numeric_limits<uint16_t>::max() > iso3166_2stringTable.size());
|
||||
subdivNameMap.push_back({key, (uint16_t)iso3166_2stringTable.size()});
|
||||
iso3166_2stringTable.append(entry.value(QLatin1String("name")).toString().toUtf8());
|
||||
iso3166_2stringTable.append('\0');
|
||||
|
||||
const auto parentKey = IsoCodes::parentCodeToKey(entry.value(QLatin1String("parent")).toString());
|
||||
if (parentKey) {
|
||||
subdivParentMap.push_back({key, parentKey});
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(subdivNameMap.begin(), subdivNameMap.end());
|
||||
std::sort(subdivParentMap.begin(), subdivParentMap.end());
|
||||
|
||||
// write out binary cache file
|
||||
QFile cache(cacheFilePath);
|
||||
if (!cache.open(QFile::WriteOnly)) {
|
||||
qCWarning(KI18NLD) << "Failed to write ISO 3166-2 cache:" << cache.errorString() << cache.fileName();
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t n = Iso3166_2CacheHeader;
|
||||
cache.write(reinterpret_cast<const char *>(&n), 4); // header
|
||||
n = subdivNameMap.size();
|
||||
cache.write(reinterpret_cast<const char *>(&n), 4); // size of the name map
|
||||
for (auto entry : subdivNameMap) {
|
||||
cache.write(reinterpret_cast<const char *>(&entry), sizeof(entry));
|
||||
}
|
||||
n = subdivParentMap.size();
|
||||
cache.write(reinterpret_cast<const char *>(&n), 4); // size of the hierarchy map
|
||||
for (auto entry : subdivParentMap) {
|
||||
cache.write(reinterpret_cast<const char *>(&entry), sizeof(entry));
|
||||
}
|
||||
cache.write(iso3166_2stringTable);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2023 Volker Krause <vkrause@kde.org>
|
||||
SPDX-License-Identifier: CC0-1.0
|
||||
-->
|
||||
<RCC>
|
||||
<qresource prefix="/org.kde.ki18n/iso-codes/cache/">
|
||||
<file>iso_3166-1</file>
|
||||
<file>iso_3166-2</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef ISOCODESCACHE_P_H
|
||||
#define ISOCODESCACHE_P_H
|
||||
|
||||
#include "mapentry_p.h"
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QStringView>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
class QFile;
|
||||
|
||||
/** Cache for iso-codes JSON data. */
|
||||
class IsoCodesCache
|
||||
{
|
||||
public:
|
||||
~IsoCodesCache();
|
||||
|
||||
static IsoCodesCache *instance();
|
||||
|
||||
void loadIso3166_1();
|
||||
void loadIso3166_2();
|
||||
|
||||
uint32_t countryCount() const;
|
||||
const MapEntry<uint16_t> *countryNameMapBegin() const;
|
||||
inline const MapEntry<uint16_t> *countryNameMapEnd() const
|
||||
{
|
||||
return countryNameMapBegin() + countryCount();
|
||||
}
|
||||
const MapEntry<uint16_t> *countryAlpha3MapBegin() const;
|
||||
inline const MapEntry<uint16_t> *countryAlpha3MapEnd() const
|
||||
{
|
||||
return countryAlpha3MapBegin() + countryCount();
|
||||
}
|
||||
const char *countryStringTableLookup(uint16_t offset) const;
|
||||
|
||||
uint32_t subdivisionCount() const;
|
||||
const MapEntry<uint32_t> *subdivisionNameMapBegin() const;
|
||||
inline const MapEntry<uint32_t> *subdivisionNameMapEnd() const
|
||||
{
|
||||
return subdivisionNameMapBegin() + subdivisionCount();
|
||||
}
|
||||
uint32_t subdivisionHierachyMapSize() const;
|
||||
const MapEntry<uint32_t> *subdivisionParentMapBegin() const;
|
||||
inline const MapEntry<uint32_t> *subdivisionParentMapEnd() const
|
||||
{
|
||||
return subdivisionParentMapBegin() + subdivisionHierachyMapSize();
|
||||
}
|
||||
const char *subdivisionStringTableLookup(uint16_t offset) const;
|
||||
|
||||
static void createIso3166_1Cache(const QString &isoCodesPath, const QString &cacheFilePath);
|
||||
static void createIso3166_2Cache(const QString &isoCodesPath, const QString &cacheFilePath);
|
||||
|
||||
private:
|
||||
bool loadIso3166_1Cache();
|
||||
bool loadIso3166_2Cache();
|
||||
|
||||
std::unique_ptr<QFile> m_iso3166_1CacheFile;
|
||||
const uint8_t *m_iso3166_1CacheData = nullptr;
|
||||
std::size_t m_iso3166_1CacheSize = 0;
|
||||
std::unique_ptr<QFile> m_iso3166_2CacheFile;
|
||||
const uint8_t *m_iso3166_2CacheData = nullptr;
|
||||
std::size_t m_iso3166_2CacheSize = 0;
|
||||
};
|
||||
|
||||
#endif // ISOCODESCACHE_H
|
||||
@@ -0,0 +1,428 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "kcountry.h"
|
||||
#include "isocodes_p.h"
|
||||
#include "isocodescache_p.h"
|
||||
#include "kcatalog_p.h"
|
||||
#include "klocalizedstring.h"
|
||||
#include "logging.h"
|
||||
#include "spatial_index_p.h"
|
||||
#include "timezonedata_p.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
using namespace Qt::Literals;
|
||||
|
||||
static_assert(sizeof(KCountry) == 2);
|
||||
|
||||
KCountry::KCountry()
|
||||
: d(0)
|
||||
{
|
||||
}
|
||||
|
||||
KCountry::KCountry(const KCountry &) = default;
|
||||
KCountry::~KCountry() = default;
|
||||
|
||||
KCountry &KCountry::operator=(const KCountry &) = default;
|
||||
|
||||
bool KCountry::operator==(const KCountry &other) const
|
||||
{
|
||||
return d == other.d;
|
||||
}
|
||||
|
||||
bool KCountry::operator!=(const KCountry &other) const
|
||||
{
|
||||
return d != other.d;
|
||||
}
|
||||
|
||||
bool KCountry::isValid() const
|
||||
{
|
||||
return d != 0;
|
||||
}
|
||||
|
||||
QString KCountry::alpha2() const
|
||||
{
|
||||
if (d == 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
QString code(2, QLatin1Char('\0'));
|
||||
code[0] = QLatin1Char(d >> 8);
|
||||
code[1] = QLatin1Char(d & 0xff);
|
||||
return code;
|
||||
}
|
||||
|
||||
QString KCountry::alpha3() const
|
||||
{
|
||||
const auto cache = IsoCodesCache::instance();
|
||||
const auto it = std::find_if(cache->countryAlpha3MapBegin(), cache->countryAlpha3MapEnd(), [this](auto entry) {
|
||||
return entry.value == d;
|
||||
});
|
||||
if (it != cache->countryAlpha3MapEnd()) {
|
||||
uint16_t alpha3Key = (*it).key;
|
||||
QString code(3, QLatin1Char('\0'));
|
||||
code[2] = QLatin1Char(IsoCodes::mapFromAlphaNumKey(alpha3Key));
|
||||
alpha3Key /= IsoCodes::AlphaNumKeyFactor;
|
||||
code[1] = QLatin1Char(IsoCodes::mapFromAlphaNumKey(alpha3Key));
|
||||
alpha3Key /= IsoCodes::AlphaNumKeyFactor;
|
||||
code[0] = QLatin1Char(IsoCodes::mapFromAlphaNumKey(alpha3Key));
|
||||
return code;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
QString KCountry::name() const
|
||||
{
|
||||
if (d == 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto cache = IsoCodesCache::instance();
|
||||
cache->loadIso3166_1();
|
||||
const auto it = std::lower_bound(cache->countryNameMapBegin(), cache->countryNameMapEnd(), d);
|
||||
if (it != cache->countryNameMapEnd() && (*it).key == d) {
|
||||
return i18nd("iso_3166-1", cache->countryStringTableLookup((*it).value));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
QString KCountry::emojiFlag() const
|
||||
{
|
||||
if (d == 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
QString flag;
|
||||
char flagA[] = "\xF0\x9F\x87\xA6";
|
||||
flagA[3] = 0xA6 + ((d >> 8) - 'A');
|
||||
flag += QString::fromUtf8(flagA);
|
||||
flagA[3] = 0xA6 + ((d & 0xff) - 'A');
|
||||
flag += QString::fromUtf8(flagA);
|
||||
return flag;
|
||||
}
|
||||
|
||||
QLocale::Country KCountry::country() const
|
||||
{
|
||||
if (d == 0) {
|
||||
return QLocale::AnyCountry;
|
||||
}
|
||||
|
||||
return QLocale::codeToTerritory(alpha2());
|
||||
}
|
||||
|
||||
QList<const char *> KCountry::timeZoneIds() const
|
||||
{
|
||||
QList<const char *> tzs;
|
||||
if (d == 0) {
|
||||
return tzs;
|
||||
}
|
||||
|
||||
const auto countryIt = std::lower_bound(TimezoneData::countryTimezoneMapBegin(), TimezoneData::countryTimezoneMapEnd(), d);
|
||||
if (countryIt != TimezoneData::countryTimezoneMapEnd() && (*countryIt).key == d) {
|
||||
tzs.push_back(TimezoneData::ianaIdLookup((*countryIt).value));
|
||||
return tzs;
|
||||
}
|
||||
|
||||
const auto [subdivBegin, subdivEnd] =
|
||||
std::equal_range(TimezoneData::subdivisionTimezoneMapBegin(), TimezoneData::subdivisionTimezoneMapEnd(), d, [](auto lhs, auto rhs) {
|
||||
if constexpr (std::is_same_v<decltype(lhs), uint16_t>)
|
||||
return lhs < (rhs.key >> 16);
|
||||
else
|
||||
return (lhs.key >> 16) < rhs;
|
||||
});
|
||||
for (auto it = subdivBegin; it != subdivEnd; ++it) {
|
||||
const auto tzId = TimezoneData::ianaIdLookup((*it).value);
|
||||
if (!tzs.contains(tzId)) {
|
||||
tzs.push_back(tzId);
|
||||
}
|
||||
}
|
||||
|
||||
return tzs;
|
||||
}
|
||||
|
||||
QString KCountry::currencyCode() const
|
||||
{
|
||||
if (d == 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
QString currency;
|
||||
const auto ls = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript, country());
|
||||
for (const auto &l : ls) {
|
||||
if (currency.isEmpty()) {
|
||||
currency = l.currencySymbol(QLocale::CurrencyIsoCode);
|
||||
} else if (currency != l.currencySymbol(QLocale::CurrencyIsoCode)) {
|
||||
qCDebug(KI18NLD) << "conflicting currency information in QLocale for" << alpha2();
|
||||
return {};
|
||||
}
|
||||
}
|
||||
return currency;
|
||||
}
|
||||
|
||||
QList<KCountrySubdivision> KCountry::subdivisions() const
|
||||
{
|
||||
if (d == 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
QList<KCountrySubdivision> l;
|
||||
auto cache = IsoCodesCache::instance();
|
||||
cache->loadIso3166_2();
|
||||
// we don't have a country->subdivisions map, instead we use the full list of subdivisions
|
||||
// (which is sorted by country due to the country being in the two most significant bytes of its key),
|
||||
// and check the child->parent subdivision map for root elements
|
||||
auto it = std::lower_bound(cache->subdivisionNameMapBegin(), cache->subdivisionNameMapEnd(), d, [](auto lhs, auto rhs) {
|
||||
return (lhs.key >> 16) < rhs;
|
||||
});
|
||||
|
||||
auto [parentBegin, parentEnd] = std::equal_range(cache->subdivisionParentMapBegin(), cache->subdivisionParentMapEnd(), d, [](auto lhs, auto rhs) {
|
||||
if constexpr (std::is_same_v<decltype(lhs), uint16_t>)
|
||||
return lhs < (rhs.key >> 16);
|
||||
else
|
||||
return (lhs.key >> 16) < rhs;
|
||||
});
|
||||
|
||||
for (; it != cache->subdivisionNameMapEnd() && ((*it).key >> 16) == d; ++it) {
|
||||
if (!std::binary_search(parentBegin, parentEnd, (*it).key)) {
|
||||
KCountrySubdivision s;
|
||||
s.d = (*it).key;
|
||||
l.push_back(s);
|
||||
}
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
static uint16_t validatedAlpha2Key(uint16_t alpha2Key)
|
||||
{
|
||||
if (!alpha2Key) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto cache = IsoCodesCache::instance();
|
||||
cache->loadIso3166_1();
|
||||
const auto it = std::lower_bound(cache->countryNameMapBegin(), cache->countryNameMapEnd(), alpha2Key);
|
||||
if (it != cache->countryNameMapEnd() && (*it).key == alpha2Key) {
|
||||
return alpha2Key;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
KCountry KCountry::fromAlpha2(QStringView alpha2Code)
|
||||
{
|
||||
KCountry c;
|
||||
c.d = validatedAlpha2Key(IsoCodes::alpha2CodeToKey(alpha2Code));
|
||||
return c;
|
||||
}
|
||||
|
||||
KCountry KCountry::fromAlpha2(const char *alpha2Code)
|
||||
{
|
||||
KCountry c;
|
||||
if (!alpha2Code) {
|
||||
return c;
|
||||
}
|
||||
c.d = validatedAlpha2Key(IsoCodes::alpha2CodeToKey(alpha2Code, std::strlen(alpha2Code)));
|
||||
return c;
|
||||
}
|
||||
|
||||
static uint16_t alpha3Lookup(uint16_t alpha3Key)
|
||||
{
|
||||
if (!alpha3Key) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto cache = IsoCodesCache::instance();
|
||||
cache->loadIso3166_1();
|
||||
const auto it = std::lower_bound(cache->countryAlpha3MapBegin(), cache->countryAlpha3MapEnd(), alpha3Key);
|
||||
if (it != cache->countryAlpha3MapEnd() && (*it).key == alpha3Key) {
|
||||
return (*it).value;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
KCountry KCountry::fromAlpha3(QStringView alpha3Code)
|
||||
{
|
||||
KCountry c;
|
||||
c.d = alpha3Lookup(IsoCodes::alpha3CodeToKey(alpha3Code));
|
||||
return c;
|
||||
}
|
||||
|
||||
KCountry KCountry::fromAlpha3(const char *alpha3Code)
|
||||
{
|
||||
KCountry c;
|
||||
if (!alpha3Code) {
|
||||
return c;
|
||||
}
|
||||
c.d = alpha3Lookup(IsoCodes::alpha3CodeToKey(alpha3Code, std::strlen(alpha3Code)));
|
||||
return c;
|
||||
}
|
||||
|
||||
KCountry KCountry::fromLocation(float latitude, float longitude)
|
||||
{
|
||||
const auto entry = SpatialIndex::lookup(latitude, longitude);
|
||||
KCountry c;
|
||||
c.d = entry.m_subdiv >> 16;
|
||||
return c;
|
||||
}
|
||||
|
||||
KCountry KCountry::fromQLocale(QLocale::Country country)
|
||||
{
|
||||
return fromAlpha2(QLocale::territoryToCode(country).data());
|
||||
}
|
||||
|
||||
static QString normalizeCountryName(QStringView name)
|
||||
{
|
||||
QString res;
|
||||
res.reserve(name.size());
|
||||
for (const auto c : name) {
|
||||
// the following needs to be done fairly fine-grained, as this can easily mess up scripts
|
||||
// that rely on some non-letter characters to work
|
||||
// all values used below were obtained by similar code in KContacts, which used to do
|
||||
// a full offline pre-computation of this and checked for ambiguities introduced by too
|
||||
// aggressive normalization
|
||||
switch (c.category()) {
|
||||
// strip decorative elements that don't contribute to identification (parenthesis, dashes, quotes, etc)
|
||||
case QChar::Punctuation_Connector:
|
||||
case QChar::Punctuation_Dash:
|
||||
case QChar::Punctuation_Open:
|
||||
case QChar::Punctuation_Close:
|
||||
case QChar::Punctuation_InitialQuote:
|
||||
case QChar::Punctuation_FinalQuote:
|
||||
case QChar::Punctuation_Other:
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (c.isSpace()) {
|
||||
if (!res.isEmpty() && !res.back().isSpace()) {
|
||||
res.push_back(' '_L1);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// if the character has a canonical decomposition skip the combining diacritic markers following it
|
||||
// this works particularly well for Latin, but messes up Hangul
|
||||
if (c.script() != QChar::Script_Hangul && c.decompositionTag() == QChar::Canonical) {
|
||||
res.push_back(c.decomposition().at(0).toCaseFolded());
|
||||
} else {
|
||||
res.push_back(c.toCaseFolded());
|
||||
}
|
||||
}
|
||||
|
||||
return res.trimmed();
|
||||
}
|
||||
|
||||
// check is @p needle is a space-separated substring of haystack
|
||||
static bool isSeparatedSubstring(QStringView haystack, QStringView needle)
|
||||
{
|
||||
auto idx = haystack.indexOf(needle);
|
||||
if (idx < 0) {
|
||||
return false;
|
||||
}
|
||||
if (idx > 0 && !haystack[idx - 1].isSpace()) {
|
||||
return false;
|
||||
}
|
||||
idx += needle.size();
|
||||
return idx >= haystack.size() || haystack[idx].isSpace();
|
||||
}
|
||||
|
||||
static void checkSubstringMatch(QStringView lhs, QStringView rhs, uint16_t code, uint16_t &result)
|
||||
{
|
||||
if (result == std::numeric_limits<uint16_t>::max() || result == code || rhs.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
const auto matches = isSeparatedSubstring(lhs, rhs) || isSeparatedSubstring(rhs, lhs);
|
||||
|
||||
if (!matches) {
|
||||
return;
|
||||
}
|
||||
result = result == 0 ? code : std::numeric_limits<uint16_t>::max();
|
||||
}
|
||||
|
||||
KCountry KCountry::fromName(QStringView name)
|
||||
{
|
||||
if (name.isEmpty()) {
|
||||
return {};
|
||||
}
|
||||
const auto normalizedName = normalizeCountryName(name);
|
||||
|
||||
auto cache = IsoCodesCache::instance();
|
||||
cache->loadIso3166_1();
|
||||
|
||||
uint16_t substrMatch = 0;
|
||||
|
||||
// check untranslated names
|
||||
for (auto it = cache->countryNameMapBegin(); it != cache->countryNameMapEnd(); ++it) {
|
||||
const auto normalizedCountry = normalizeCountryName(QString::fromUtf8(cache->countryStringTableLookup((*it).value)));
|
||||
if (normalizedName == normalizedCountry) {
|
||||
KCountry c;
|
||||
c.d = (*it).key;
|
||||
return c;
|
||||
}
|
||||
checkSubstringMatch(normalizedName, normalizedCountry, (*it).key, substrMatch);
|
||||
}
|
||||
|
||||
// check translated names
|
||||
const auto langs = KCatalog::availableCatalogLanguages("iso_3166-1");
|
||||
for (const auto &lang : langs) {
|
||||
const auto catalog = KCatalog("iso_3166-1", lang);
|
||||
for (auto it = cache->countryNameMapBegin(); it != cache->countryNameMapEnd(); ++it) {
|
||||
const auto normalizedCountry = normalizeCountryName(catalog.translate(cache->countryStringTableLookup((*it).value)));
|
||||
if (normalizedName == normalizedCountry) {
|
||||
KCountry c;
|
||||
c.d = (*it).key;
|
||||
return c;
|
||||
}
|
||||
checkSubstringMatch(normalizedName, normalizedCountry, (*it).key, substrMatch);
|
||||
}
|
||||
}
|
||||
|
||||
// unique prefix/suffix match
|
||||
if (substrMatch != std::numeric_limits<uint16_t>::max() && substrMatch != 0) {
|
||||
KCountry c;
|
||||
c.d = substrMatch;
|
||||
return c;
|
||||
}
|
||||
|
||||
// fallback to code lookups
|
||||
if (normalizedName.size() == 3) {
|
||||
return fromAlpha3(normalizedName);
|
||||
}
|
||||
if (normalizedName.size() == 2) {
|
||||
return fromAlpha2(normalizedName);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
QList<KCountry> KCountry::allCountries()
|
||||
{
|
||||
QList<KCountry> l;
|
||||
auto cache = IsoCodesCache::instance();
|
||||
cache->loadIso3166_1();
|
||||
l.reserve(cache->countryCount());
|
||||
std::transform(cache->countryNameMapBegin(), cache->countryNameMapEnd(), std::back_inserter(l), [](auto entry) {
|
||||
KCountry c;
|
||||
c.d = entry.key;
|
||||
return c;
|
||||
});
|
||||
return l;
|
||||
}
|
||||
|
||||
QStringList KCountry::timeZoneIdsStringList() const
|
||||
{
|
||||
const auto tzIds = timeZoneIds();
|
||||
QStringList l;
|
||||
l.reserve(tzIds.size());
|
||||
std::transform(tzIds.begin(), tzIds.end(), std::back_inserter(l), [](const char *tzId) {
|
||||
return QString::fromUtf8(tzId);
|
||||
});
|
||||
return l;
|
||||
}
|
||||
|
||||
#include "moc_kcountry.cpp"
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef KCOUNTRY_H
|
||||
#define KCOUNTRY_H
|
||||
|
||||
#include "ki18nlocaledata_export.h"
|
||||
|
||||
#include <QLocale>
|
||||
#include <QMetaType>
|
||||
|
||||
#include "kcountrysubdivision.h"
|
||||
|
||||
class KCountry;
|
||||
|
||||
namespace KTimeZone
|
||||
{
|
||||
KI18NLOCALEDATA_EXPORT KCountry country(const char *);
|
||||
}
|
||||
|
||||
/**
|
||||
* @class KCountry kcountry.h <KCountry>
|
||||
*
|
||||
* Information about an ISO 3166-1 country.
|
||||
*
|
||||
* The information provided here are aggregated from the following sources:
|
||||
* - [iso-codes](https://salsa.debian.org/iso-codes-team/iso-codes/)
|
||||
* - [timezone-boundary-builder](https://github.com/evansiroky/timezone-boundary-builder/)
|
||||
* - [OSM](https://openstreetmap.org)
|
||||
* - [CLDR](http://cldr.unicode.org/)
|
||||
*
|
||||
* @note This requires the iso-codes data files and translation catalogs to be available at runtime.
|
||||
*
|
||||
* @since 5.88
|
||||
*/
|
||||
class KI18NLOCALEDATA_EXPORT KCountry
|
||||
{
|
||||
Q_GADGET
|
||||
Q_PROPERTY(QString alpha2 READ alpha2)
|
||||
Q_PROPERTY(QString alpha3 READ alpha3)
|
||||
Q_PROPERTY(QString name READ name)
|
||||
Q_PROPERTY(QString emojiFlag READ emojiFlag)
|
||||
Q_PROPERTY(QString currencyCode READ currencyCode)
|
||||
Q_PROPERTY(QList<KCountrySubdivision> subdivisions READ subdivisions)
|
||||
Q_PROPERTY(QStringList timeZoneIds READ timeZoneIdsStringList)
|
||||
|
||||
public:
|
||||
/** Creates an invalid/empty KCountry instance.
|
||||
* See the fromX() methods for creating a valid instance.
|
||||
*/
|
||||
KCountry();
|
||||
KCountry(const KCountry &);
|
||||
~KCountry();
|
||||
KCountry &operator=(const KCountry &);
|
||||
|
||||
bool operator==(const KCountry &other) const;
|
||||
bool operator!=(const KCountry &other) const;
|
||||
|
||||
/** Returns @c false if this is an empty/invalid/default constructed instance, @c true otherwise. */
|
||||
bool isValid() const;
|
||||
|
||||
/** ISO 3166-1 alpha 2 country code. */
|
||||
QString alpha2() const;
|
||||
/** ISO 3166-1 alpha 3 country code. */
|
||||
QString alpha3() const;
|
||||
/** Translated country name. */
|
||||
QString name() const;
|
||||
/** Returns the Unicode flag emoji for this country. */
|
||||
QString emojiFlag() const;
|
||||
/** Returns the QLocale::Country value matching this country, or QLocale::AnyCountry if there is none. */
|
||||
QLocale::Country country() const; // TODO better name?
|
||||
|
||||
/** Timezones in use in this country. */
|
||||
QList<const char *> timeZoneIds() const;
|
||||
/** Currency used in this country as ISO 4217 code. */
|
||||
QString currencyCode() const;
|
||||
/** Highest level of ISO 3166-2 country subdivisions.
|
||||
* If there is only one level of subdivisions this lists all of them,
|
||||
* for countries with multiple levels, this only includes the top-level
|
||||
* subdivisions (ie. those having no parent subdivision).
|
||||
* @note: This can be empty.
|
||||
*/
|
||||
QList<KCountrySubdivision> subdivisions() const;
|
||||
|
||||
/** Create a KCountry instance from an ISO 3166-1 alpha 2 code. */
|
||||
static KCountry fromAlpha2(QStringView alpha2Code);
|
||||
/** Create a KCountry instance from an ISO 3166-1 alpha 2 code. */
|
||||
static KCountry fromAlpha2(const char *alpha2Code);
|
||||
/** Create a KCountry instance from an ISO 3166-1 alpha 3 code. */
|
||||
static KCountry fromAlpha3(QStringView alpha3Code);
|
||||
/** Create a KCountry instance from an ISO 3166-1 alpha 3 code. */
|
||||
static KCountry fromAlpha3(const char *alpha3Code);
|
||||
/** Looks up the country at the given geographic coordinate.
|
||||
* This can return an invalid object if the country could not be determined. This can happen in a number of cases:
|
||||
* - on oceans
|
||||
* - in polar regions
|
||||
* - close to a land border
|
||||
* - in disputed territories
|
||||
*/
|
||||
static KCountry fromLocation(float latitude, float longitude);
|
||||
/** Returns a KCountry instance matching the given QLocale::Country code. */
|
||||
static KCountry fromQLocale(QLocale::Country country);
|
||||
/** Attempts to identify the country from the given name.
|
||||
* The name can be in any language.
|
||||
*/
|
||||
static KCountry fromName(QStringView name);
|
||||
|
||||
/** List all countries. */
|
||||
static QList<KCountry> allCountries();
|
||||
|
||||
private:
|
||||
KI18NLOCALEDATA_NO_EXPORT QStringList timeZoneIdsStringList() const;
|
||||
|
||||
friend class KCountrySubdivision;
|
||||
friend KI18NLOCALEDATA_EXPORT KCountry KTimeZone::country(const char *);
|
||||
uint16_t d;
|
||||
};
|
||||
|
||||
Q_DECLARE_TYPEINFO(KCountry, Q_RELOCATABLE_TYPE);
|
||||
|
||||
#endif // KCOUNTRY_H
|
||||
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "kcountrysubdivision.h"
|
||||
#include "isocodes_p.h"
|
||||
#include "isocodescache_p.h"
|
||||
#include "kcountry.h"
|
||||
#include "ki18n_logging.h"
|
||||
#include "klocalizedstring.h"
|
||||
#include "spatial_index_p.h"
|
||||
#include "timezonedata_p.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
static_assert(sizeof(KCountrySubdivision) == 4);
|
||||
|
||||
KCountrySubdivision::KCountrySubdivision()
|
||||
: d(0)
|
||||
{
|
||||
}
|
||||
|
||||
KCountrySubdivision::KCountrySubdivision(const KCountrySubdivision &) = default;
|
||||
KCountrySubdivision::~KCountrySubdivision() = default;
|
||||
KCountrySubdivision &KCountrySubdivision::operator=(const KCountrySubdivision &) = default;
|
||||
|
||||
bool KCountrySubdivision::operator==(const KCountrySubdivision &other) const
|
||||
{
|
||||
return d == other.d;
|
||||
}
|
||||
|
||||
bool KCountrySubdivision::operator!=(const KCountrySubdivision &other) const
|
||||
{
|
||||
return d != other.d;
|
||||
}
|
||||
|
||||
bool KCountrySubdivision::isValid() const
|
||||
{
|
||||
return d != 0;
|
||||
}
|
||||
|
||||
QString KCountrySubdivision::code() const
|
||||
{
|
||||
if (d == 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
QString code;
|
||||
code.reserve(6);
|
||||
code += country().alpha2();
|
||||
code += QLatin1Char('-');
|
||||
|
||||
auto key = d & 0xffff;
|
||||
while (key) {
|
||||
const auto c = IsoCodes::mapFromAlphaNumKey(key);
|
||||
if (c) {
|
||||
code.insert(3, QLatin1Char(c));
|
||||
}
|
||||
key /= IsoCodes::AlphaNumKeyFactor;
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
QString KCountrySubdivision::name() const
|
||||
{
|
||||
if (d == 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto cache = IsoCodesCache::instance();
|
||||
cache->loadIso3166_2();
|
||||
const auto it = std::lower_bound(cache->subdivisionNameMapBegin(), cache->subdivisionNameMapEnd(), d);
|
||||
if (it != cache->subdivisionNameMapEnd() && (*it).key == d) {
|
||||
return i18nd("iso_3166-2", cache->subdivisionStringTableLookup((*it).value));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
KCountry KCountrySubdivision::country() const
|
||||
{
|
||||
KCountry c;
|
||||
c.d = d >> 16;
|
||||
return c;
|
||||
}
|
||||
|
||||
KCountrySubdivision KCountrySubdivision::parent() const
|
||||
{
|
||||
KCountrySubdivision s;
|
||||
if (d == 0) {
|
||||
return s;
|
||||
}
|
||||
|
||||
auto cache = IsoCodesCache::instance();
|
||||
cache->loadIso3166_2();
|
||||
|
||||
const auto it = std::lower_bound(cache->subdivisionParentMapBegin(), cache->subdivisionParentMapEnd(), d);
|
||||
if (it != cache->subdivisionParentMapEnd() && (*it).key == d) {
|
||||
s.d = (d & 0xffff0000) | (uint32_t)(*it).value;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
QList<const char *> KCountrySubdivision::timeZoneIds() const
|
||||
{
|
||||
QList<const char *> tzs;
|
||||
if (d == 0) {
|
||||
return tzs;
|
||||
}
|
||||
|
||||
const auto [subdivBegin, subdivEnd] = std::equal_range(TimezoneData::subdivisionTimezoneMapBegin(), TimezoneData::subdivisionTimezoneMapEnd(), d);
|
||||
if (subdivBegin != subdivEnd) {
|
||||
tzs.reserve(std::distance(subdivBegin, subdivEnd));
|
||||
for (auto it = subdivBegin; it != subdivEnd; ++it) {
|
||||
tzs.push_back(TimezoneData::ianaIdLookup((*it).value));
|
||||
}
|
||||
return tzs;
|
||||
}
|
||||
|
||||
const auto countryIt = std::lower_bound(TimezoneData::countryTimezoneMapBegin(), TimezoneData::countryTimezoneMapEnd(), uint16_t(d >> 16));
|
||||
if (countryIt != TimezoneData::countryTimezoneMapEnd() && (*countryIt).key == (d >> 16)) {
|
||||
tzs.push_back(TimezoneData::ianaIdLookup((*countryIt).value));
|
||||
}
|
||||
|
||||
return tzs;
|
||||
}
|
||||
|
||||
QList<KCountrySubdivision> KCountrySubdivision::subdivisions() const
|
||||
{
|
||||
if (d == 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
QList<KCountrySubdivision> l;
|
||||
auto cache = IsoCodesCache::instance();
|
||||
cache->loadIso3166_2();
|
||||
// we don't have a parent->child map, instead we use the child->parent map
|
||||
// that is sorted by country (due to the country being in the two most significant bytes of its key),
|
||||
// so we don't need to do a full sequential search here
|
||||
auto it = std::lower_bound(cache->subdivisionParentMapBegin(), cache->subdivisionParentMapEnd(), d >> 16, [](auto lhs, auto rhs) {
|
||||
return (lhs.key >> 16) < rhs;
|
||||
});
|
||||
for (; it != cache->subdivisionParentMapEnd() && ((*it).key >> 16) == (d >> 16); ++it) {
|
||||
if ((*it).value == (d & 0xffff)) {
|
||||
KCountrySubdivision s;
|
||||
s.d = (*it).key;
|
||||
l.push_back(s);
|
||||
}
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
static uint32_t validatedSubdivisionKey(uint32_t key)
|
||||
{
|
||||
if (!key) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto cache = IsoCodesCache::instance();
|
||||
cache->loadIso3166_2();
|
||||
|
||||
const auto it = std::lower_bound(cache->subdivisionNameMapBegin(), cache->subdivisionNameMapEnd(), key);
|
||||
if (it != cache->subdivisionNameMapEnd() && (*it).key == key) {
|
||||
return key;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
KCountrySubdivision KCountrySubdivision::fromCode(QStringView code)
|
||||
{
|
||||
KCountrySubdivision s;
|
||||
s.d = validatedSubdivisionKey(IsoCodes::subdivisionCodeToKey(code));
|
||||
return s;
|
||||
}
|
||||
|
||||
KCountrySubdivision KCountrySubdivision::fromCode(const char *code)
|
||||
{
|
||||
KCountrySubdivision s;
|
||||
if (code) {
|
||||
s.d = validatedSubdivisionKey(IsoCodes::subdivisionCodeToKey(code, std::strlen(code)));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
KCountrySubdivision KCountrySubdivision::fromLocation(float latitude, float longitude)
|
||||
{
|
||||
const auto entry = SpatialIndex::lookup(latitude, longitude);
|
||||
KCountrySubdivision s;
|
||||
if (entry.m_subdiv & 0xffff) {
|
||||
s.d = entry.m_subdiv;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
QStringList KCountrySubdivision::timeZoneIdsStringList() const
|
||||
{
|
||||
const auto tzIds = timeZoneIds();
|
||||
QStringList l;
|
||||
l.reserve(tzIds.size());
|
||||
std::transform(tzIds.begin(), tzIds.end(), std::back_inserter(l), [](const char *tzId) {
|
||||
return QString::fromUtf8(tzId);
|
||||
});
|
||||
return l;
|
||||
}
|
||||
|
||||
#include "moc_kcountrysubdivision.cpp"
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef KCOUNTRYSUBDIVISION_H
|
||||
#define KCOUNTRYSUBDIVISION_H
|
||||
|
||||
#include "ki18nlocaledata_export.h"
|
||||
|
||||
#include <QMetaType>
|
||||
|
||||
class KCountry;
|
||||
|
||||
/**
|
||||
* @class KCountrySubdivision kcountrysubdivision.h <KCountrySubdivision>
|
||||
*
|
||||
* Information about an ISO 3166-2 country subdivision.
|
||||
*
|
||||
* @note This requires the [iso-codes](https://salsa.debian.org/iso-codes-team/iso-codes/)
|
||||
* data files and translation catalogs to be available at runtime.
|
||||
* @see KCountry for the data sources.
|
||||
*
|
||||
* @since 5.88
|
||||
*/
|
||||
class KI18NLOCALEDATA_EXPORT KCountrySubdivision
|
||||
{
|
||||
Q_GADGET
|
||||
Q_PROPERTY(QString code READ code)
|
||||
Q_PROPERTY(QString name READ name)
|
||||
Q_PROPERTY(KCountry country READ country)
|
||||
Q_PROPERTY(KCountrySubdivision parent READ parent)
|
||||
Q_PROPERTY(QList<KCountrySubdivision> subdivisions READ subdivisions)
|
||||
Q_PROPERTY(QStringList timeZoneIds READ timeZoneIdsStringList)
|
||||
|
||||
public:
|
||||
/** Creates an invalid/empty KCountrySubdivision instance.
|
||||
* See the fromX() methods for creating a valid instance.
|
||||
*/
|
||||
KCountrySubdivision();
|
||||
KCountrySubdivision(const KCountrySubdivision &);
|
||||
~KCountrySubdivision();
|
||||
KCountrySubdivision &operator=(const KCountrySubdivision &);
|
||||
|
||||
bool operator==(const KCountrySubdivision &other) const;
|
||||
bool operator!=(const KCountrySubdivision &other) const;
|
||||
|
||||
/** Returns @c false if this is an empty/invalid/default constructed instance, @c true otherwise. */
|
||||
bool isValid() const;
|
||||
|
||||
/** ISO 3166-2 country subdivision code. */
|
||||
QString code() const;
|
||||
/** Translated country subdivision name. */
|
||||
QString name() const;
|
||||
/** Country this subdivision belongs to. */
|
||||
KCountry country() const;
|
||||
/** Parent subdivision, if this is a subdivision of another subdivision.
|
||||
* Returns an invalid element for top-level subdivisions.
|
||||
*/
|
||||
KCountrySubdivision parent() const;
|
||||
|
||||
/** Timezones in use in this country subdivision. */
|
||||
// for subdivisions we have to generate that by polygon intersections in QGIS -> POC
|
||||
QList<const char *> timeZoneIds() const;
|
||||
/** Subdivisions of this subdivision, if any.
|
||||
* This is only relevant for countries with multiple ISO 3166-2 subdivision levels.
|
||||
*/
|
||||
QList<KCountrySubdivision> subdivisions() const;
|
||||
|
||||
/** Create a KCountrySubdivision instance from an ISO 3166-2 code. */
|
||||
static KCountrySubdivision fromCode(QStringView code);
|
||||
/** Create a KCountrySubdivision instance from an ISO 3166-2 code. */
|
||||
static KCountrySubdivision fromCode(const char *code);
|
||||
/** Looks up the country subdivision at the given geographic coordinate.
|
||||
* This can return an invalid object if the country subdivision could not be determined. This can happen in a number of cases:
|
||||
* - on oceans
|
||||
* - in polar regions
|
||||
* - close to a land border
|
||||
* - in disputed territories
|
||||
* @note It is possible for KCountry::fromLocation() to return a valid result despite
|
||||
* this method returning an invalid result.
|
||||
*/
|
||||
static KCountrySubdivision fromLocation(float latitude, float longitude);
|
||||
|
||||
private:
|
||||
KI18NLOCALEDATA_NO_EXPORT QStringList timeZoneIdsStringList() const;
|
||||
|
||||
friend class KCountry;
|
||||
uint32_t d;
|
||||
};
|
||||
|
||||
Q_DECLARE_TYPEINFO(KCountrySubdivision, Q_RELOCATABLE_TYPE);
|
||||
|
||||
#endif // KCOUNTRYSUBDIVISION_H
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "ktimezone.h"
|
||||
#include "data/timezone_name_table.cpp"
|
||||
#include "kcountry.h"
|
||||
#include "spatial_index_p.h"
|
||||
|
||||
#include <QTimeZone>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
const char *KTimeZone::fromLocation(float latitude, float longitude)
|
||||
{
|
||||
const auto entry = SpatialIndex::lookup(latitude, longitude);
|
||||
return timezone_name_table + entry.m_tz;
|
||||
}
|
||||
|
||||
KCountry KTimeZone::country(const char *ianaId)
|
||||
{
|
||||
// Asia/Bangkok is special as it's the only "regular" IANA tz that covers more than one country
|
||||
// (northern Vietnam and Thailand in this case), QTimeZone however reports it as Thailand.
|
||||
if (!ianaId || std::strcmp(ianaId, "") == 0 || std::strcmp(ianaId, "Asia/Bangkok") == 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return KCountry::fromQLocale(QTimeZone(ianaId).territory());
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef KTIMEZONE_H
|
||||
#define KTIMEZONE_H
|
||||
|
||||
#include "ki18nlocaledata_export.h"
|
||||
|
||||
class KCountry;
|
||||
|
||||
/** Timezone localization methods.
|
||||
* @since 5.88
|
||||
*/
|
||||
namespace KTimeZone // TODO name clash with kdelibs4support!?
|
||||
{
|
||||
/** Returns the timezone at the given geo coordinate. */
|
||||
KI18NLOCALEDATA_EXPORT const char *fromLocation(float latitude, float longitude);
|
||||
|
||||
/** Returns the country a timezone is in.
|
||||
* This only returns a country if the timezone covers exactly one country
|
||||
* (but not necessarily the entire country).
|
||||
* For obtaining any country covered by a timezone, see QTimeZone::territory.
|
||||
*/
|
||||
KI18NLOCALEDATA_EXPORT KCountry country(const char *ianaId);
|
||||
|
||||
}
|
||||
|
||||
#endif // KTIMEZONE_H
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef MAPENTRY_P_H
|
||||
#define MAPENTRY_P_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
|
||||
template<typename KeyType>
|
||||
struct MapEntry {
|
||||
KeyType key;
|
||||
uint16_t value;
|
||||
};
|
||||
|
||||
template<typename KeyType>
|
||||
constexpr inline bool operator<(MapEntry<KeyType> lhs, MapEntry<KeyType> rhs)
|
||||
{
|
||||
return lhs.key < rhs.key;
|
||||
}
|
||||
|
||||
template<typename KeyType>
|
||||
constexpr inline bool operator<(MapEntry<KeyType> lhs, KeyType rhs)
|
||||
{
|
||||
return lhs.key < rhs;
|
||||
}
|
||||
|
||||
template<typename KeyType>
|
||||
constexpr inline bool operator<(KeyType lhs, MapEntry<KeyType> rhs)
|
||||
{
|
||||
return lhs < rhs.key;
|
||||
}
|
||||
|
||||
template<typename MapEntry, std::size_t N>
|
||||
inline constexpr bool isSortedLookupTable(const MapEntry (&map)[N])
|
||||
{
|
||||
#if __cplusplus > 201703L && defined(__GNUC__) && __GNUC__ > 9 && !defined(__clang__)
|
||||
return std::is_sorted(std::begin(map), std::end(map));
|
||||
#else
|
||||
(void)map;
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,4 @@
|
||||
# SPDX-FileCopyrightText: none
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
data
|
||||
__pycache__
|
||||
@@ -0,0 +1,108 @@
|
||||
# SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
||||
# SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
|
||||
import os
|
||||
import requests
|
||||
from qgis import *
|
||||
from qgis.core import *
|
||||
import time
|
||||
import zipfile
|
||||
from config import *
|
||||
|
||||
# Download and unpack Shapefiles
|
||||
class LayerDownloadTask(QgsTask):
|
||||
def __init__(self, url, dest):
|
||||
super().__init__('Download Shapefile', QgsTask.CanCancel)
|
||||
self.url = url
|
||||
self.dest = dest
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
QgsMessageLog.logMessage(f"Downloading and unpacking {self.dest}...", LOG_CATEGORY, Qgis.Info)
|
||||
if not os.path.exists(self.dest):
|
||||
r = requests.get(self.url)
|
||||
if r.status_code < 400:
|
||||
with open(self.dest, 'wb') as f:
|
||||
f.write(r.content)
|
||||
with zipfile.ZipFile(self.dest, 'r') as z:
|
||||
z.extractall('.')
|
||||
QgsMessageLog.logMessage(f"Downloaded and unpacked {self.dest}.", LOG_CATEGORY, Qgis.Info)
|
||||
except Exception as e:
|
||||
QgsMessageLog.logMessage(f"Exception in task: {e}", LOG_CATEGORY, Qgis.Critical)
|
||||
return True
|
||||
|
||||
|
||||
# Load and simplify Shapefile layers
|
||||
# Simplification is done to massively speed up geometry intersection computation
|
||||
# (for reference: the original KItinerary tz spatial index took 8h to compute without simplification,
|
||||
# and about 15 minutes with a Douglas Peucker simplification with a 0.001 threshold, with no practical
|
||||
# loss of precision
|
||||
class LoadLayerTask(QgsTask):
|
||||
def __init__(self, url, fileName, context, layerName):
|
||||
super().__init__(f"Loading layer {fileName}", QgsTask.CanCancel)
|
||||
self.layer = None
|
||||
self.url = url
|
||||
self.fileName = fileName
|
||||
self.context = context
|
||||
self.layerName = layerName
|
||||
self.downloadTask = LayerDownloadTask(url, fileName)
|
||||
self.addSubTask(self.downloadTask, [], QgsTask.ParentDependsOnSubTask)
|
||||
|
||||
def run(self):
|
||||
QgsMessageLog.logMessage(f"Simplifying layer {self.fileName}", LOG_CATEGORY, Qgis.Info)
|
||||
fullLayer = QgsVectorLayer(self.fileName, f"{self.fileName}-full-resolution", 'ogr')
|
||||
if not fullLayer.isValid():
|
||||
QgsMessageLog.logMessage(f"Failed to load layer {self.fileName}!", LOG_CATEGORY, Qgis.Critical)
|
||||
result = processing.run('qgis:simplifygeometries', {'INPUT': fullLayer, 'METHOD': 0, 'TOLERANCE': 0.001, 'OUTPUT': 'TEMPORARY_OUTPUT' })
|
||||
self.layer = result['OUTPUT']
|
||||
self.layer.setName(f"{self.fileName}-simplified")
|
||||
self.context[self.layerName] = self.layer
|
||||
QgsMessageLog.logMessage(f"Simplified layer {self.fileName}", LOG_CATEGORY, Qgis.Info)
|
||||
return True
|
||||
|
||||
def finished(self, result):
|
||||
QgsProject.instance().addMapLayer(self.layer)
|
||||
|
||||
|
||||
# Filter out too small elements in the ISO 3166-2 layer
|
||||
class Iso3166_2FilterTask(QgsTask):
|
||||
def __init__(self, context):
|
||||
super().__init__('Filtering ISO 3166-2 layer', QgsTask.CanCancel)
|
||||
self.context = context
|
||||
|
||||
def run(self):
|
||||
QgsMessageLog.logMessage('Filtering ISO 3166-2 layer', LOG_CATEGORY, Qgis.Info)
|
||||
subdivLayer = self.context['subdivLayer']
|
||||
toBeRemoved = []
|
||||
for feature in subdivLayer.getFeatures():
|
||||
# sic: the key is really "admin_leve" in the input file, due to length restrictions in the Shapefile...
|
||||
level = feature['admin_leve']
|
||||
country = feature['ISO3166-2'][:2]
|
||||
if not isinstance(level, str) or not isinstance(country, str):
|
||||
continue
|
||||
for filter in ISO3166_2_FILTER:
|
||||
if int(level) == filter['admin_level'] and country == filter['country']:
|
||||
toBeRemoved.append(feature.id())
|
||||
break
|
||||
subdivLayer.dataProvider().deleteFeatures(toBeRemoved)
|
||||
return True
|
||||
|
||||
|
||||
# Setup all data layers we need
|
||||
class LoadLayersTask(QgsTask):
|
||||
def __init__(self, context):
|
||||
super().__init__('Loading layers...', QgsTask.CanCancel)
|
||||
self.context = context
|
||||
self.tasks = [
|
||||
LoadLayerTask(TZDATA_URL, f"timezones.shapefile-{TZDATA_VERSION}.zip", context, 'tzLayer'),
|
||||
LoadLayerTask(ISO3166_1_URL, f"iso3166-1-boundaries.shp-{ISO3166_1_VERSION}.zip", context, 'countryLayer'),
|
||||
LoadLayerTask(ISO3166_2_URL, f"iso3166-2-boundaries.shp-{ISO3166_2_VERSION}.zip", context, 'subdivLayer')
|
||||
]
|
||||
for task in self.tasks:
|
||||
self.addSubTask(task, [], QgsTask.ParentDependsOnSubTask)
|
||||
|
||||
self.filterTask = Iso3166_2FilterTask(context)
|
||||
self.addSubTask(self.filterTask, [self.tasks[2]], QgsTask.ParentDependsOnSubTask)
|
||||
|
||||
def run(self):
|
||||
return True
|
||||
@@ -0,0 +1,372 @@
|
||||
# SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
||||
# SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
|
||||
from config import *
|
||||
import datetime
|
||||
import functools
|
||||
import os
|
||||
import pytz
|
||||
import time
|
||||
from qgis import *
|
||||
from qgis.core import *
|
||||
|
||||
xStep = xRange / (1 << zDepth)
|
||||
yStep = yRange / (1 << zDepth)
|
||||
|
||||
def z2x(z):
|
||||
x = 0
|
||||
for i in range(0, zDepth):
|
||||
x += (z & (1 << i * 2)) >> i
|
||||
return x
|
||||
|
||||
def z2y(z):
|
||||
y = 0
|
||||
for i in range(0, zDepth):
|
||||
y += (z & (1 << (1 + i * 2))) >> (i + 1)
|
||||
return y
|
||||
|
||||
def rectForZ(z, depth):
|
||||
mask = (1 << (2*(zDepth - depth))) - 1
|
||||
x = z2x(z & ~mask) * xStep + xStart
|
||||
y = z2y(z & ~mask) * yStep + yStart
|
||||
xSize = xRange / (1 << depth)
|
||||
ySize = yRange / (1 << depth)
|
||||
return QgsRectangle(x, y, x + xSize, y + ySize)
|
||||
|
||||
def tzIdToEnum(tzId):
|
||||
if not tzId:
|
||||
return 'Undefined'
|
||||
return tzId.replace('/', '_').replace('-', '_')
|
||||
|
||||
# Layer specific configuration for things considered in the spatial index
|
||||
class LayerConfig:
|
||||
def readFeatureValue(self, feature):
|
||||
return feature[self.featureKey]
|
||||
|
||||
def isValidFeature(self, feature):
|
||||
return feature != None
|
||||
|
||||
def normalizeAndFilter(self, features):
|
||||
for key in features:
|
||||
if not self.isValidFeature(key):
|
||||
del(features[key])
|
||||
return features
|
||||
|
||||
def resolveConflicts(self, features):
|
||||
out = []
|
||||
for key in features:
|
||||
out.append((key, features[key]));
|
||||
n = functools.reduce(lambda n, f: n + f[1], out, 0)
|
||||
if n > 0:
|
||||
out = [(k, v/n) for (k, v) in out]
|
||||
out = list(filter(lambda x: x[1] > featureAreaRatioThreshold, out))
|
||||
out.sort(key = lambda x: x[1], reverse = True)
|
||||
return out
|
||||
|
||||
class TzLayerConfig(LayerConfig):
|
||||
def __init__(self):
|
||||
self.layer = 'tzLayer'
|
||||
self.featureKey = 'tzid'
|
||||
|
||||
def readFeatureValue(self, feature):
|
||||
tzId = feature[self.featureKey]
|
||||
if tzId in TZID_MAP:
|
||||
return TZID_MAP[tzId]
|
||||
return tzId
|
||||
|
||||
def resolveConflicts(self, features):
|
||||
if len(features) > 1:
|
||||
tzs = list(features.keys())
|
||||
# check for conflicting timezones
|
||||
tz = pytz.timezone(tzs[0])
|
||||
if not all(self.isSameTimezone(tz, pytz.timezone(x)) for x in tzs[1:]):
|
||||
return None
|
||||
out = super().resolveConflicts(features)
|
||||
return [out[0]]
|
||||
return super().resolveConflicts(features)
|
||||
|
||||
def isSameTimezone(self, lhs, rhs):
|
||||
try:
|
||||
# hacky tz comparison, lacking access to the rules for comparing actual DST transition times
|
||||
# TODO stabilize results and ensure we capture differences due to different week boundaries
|
||||
dt = datetime.datetime.today().toordinal()
|
||||
return all(lhs.utcoffset(datetime.datetime.fromordinal(dt + 30*x)) == rhs.utcoffset(datetime.datetime.fromordinal(dt + 30*x))
|
||||
and lhs.tzname(datetime.datetime.fromordinal(dt + 30*x)) == rhs.tzname(datetime.datetime.fromordinal(dt + 30*x)) for x in range(0, 11))
|
||||
except:
|
||||
return False
|
||||
|
||||
class CountryLayerConfig(LayerConfig):
|
||||
def __init__(self):
|
||||
self.layer = 'countryLayer'
|
||||
self.featureKey = 'ISO3166-1'
|
||||
|
||||
def readFeatureValue(self, feature):
|
||||
code = feature[self.featureKey]
|
||||
if code in ISO3166_1_MAP:
|
||||
return ISO3166_1_MAP[code]
|
||||
return code
|
||||
|
||||
def normalizeAndFilter(self, features):
|
||||
if len(features) > 1:
|
||||
# apply country disambiguation
|
||||
for d in ISO3166_1_DISAMBIGUATION_MAP:
|
||||
if d[0] in features and d[1] in features:
|
||||
del(features[d[1]])
|
||||
return super().normalizeAndFilter(features)
|
||||
|
||||
def resolveConflicts(self, features):
|
||||
out = super().resolveConflicts(features)
|
||||
if len(out) > 1:
|
||||
return None
|
||||
return out
|
||||
|
||||
class SubdivLayerConfig(LayerConfig):
|
||||
def __init__(self):
|
||||
self.layer = 'subdivLayer'
|
||||
self.featureKey = 'ISO3166-2'
|
||||
|
||||
def resolveConflicts(self, features):
|
||||
out = super().resolveConflicts(features)
|
||||
if len(out) > 1:
|
||||
return None
|
||||
return out
|
||||
#
|
||||
# Parallelized spatial index computation of a single sub-tile
|
||||
#
|
||||
class SpatialIndexerSubTask(QgsTask):
|
||||
def __init__(self, context, zStart, zStartDepth):
|
||||
super().__init__('Compute spatial index sub-tile ' + str(zStart), QgsTask.CanCancel)
|
||||
self.context = context
|
||||
self.zStart = zStart
|
||||
self.zStartDepth = zStartDepth
|
||||
self.lastFeature = []
|
||||
self.exception = None
|
||||
self.result = []
|
||||
self.layerConfig = [TzLayerConfig(), CountryLayerConfig(), SubdivLayerConfig()]
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
self.computeTile(self.zStart, self.zStartDepth)
|
||||
except Exception as e:
|
||||
self.exception = e
|
||||
QgsMessageLog.logMessage('Exception in task "{}"'.format(self.exception), LOG_CATEGORY, Qgis.Info)
|
||||
return False
|
||||
return True
|
||||
|
||||
def computeTile(self, zStart, depth):
|
||||
if self.isCanceled() or depth < 1:
|
||||
return
|
||||
z = zStart
|
||||
d = depth - 1
|
||||
zIncrement = 1 << (2*d)
|
||||
for i in range(0, 4):
|
||||
# find features in the input vector layer inside our current tile
|
||||
# we cannot take shortcuts here and avoid the expensive area computation
|
||||
# as we do get spurious 0-area results for some large and disjoint polygons (FR, US, NZ, etc)
|
||||
feature = []
|
||||
featureCount = 0
|
||||
for layerConfig in self.layerConfig:
|
||||
l = {}
|
||||
rect = rectForZ(z, zDepth - d)
|
||||
rectGeo = QgsGeometry.fromRect(rect)
|
||||
for f in self.context[layerConfig.layer].getFeatures(rect):
|
||||
featureArea = f.geometry().intersection(rectGeo).area()
|
||||
if featureArea > 0.0:
|
||||
key = layerConfig.readFeatureValue(f)
|
||||
if key in l:
|
||||
l[key] += featureArea / rectGeo.area()
|
||||
else:
|
||||
l[key] = featureArea / rectGeo.area()
|
||||
feature.append(layerConfig.normalizeAndFilter(l))
|
||||
featureCount = max(featureCount, len(l))
|
||||
|
||||
# recurse on conflicts
|
||||
if depth > 1 and featureCount > 1:
|
||||
self.computeTile(z, d)
|
||||
# leaf tile, process the result
|
||||
else:
|
||||
# try to clean up any remaining conflicts
|
||||
for i in range(len(feature)):
|
||||
feature[i] = self.layerConfig[i].resolveConflicts(feature[i])
|
||||
self.resolveConflicts(feature)
|
||||
# if there's a change to the previous value, propagate to the result output
|
||||
if self.lastFeature != feature and feature != []:
|
||||
self.result.append((z, feature))
|
||||
self.lastFeature = feature
|
||||
|
||||
z += zIncrement
|
||||
|
||||
def resolveConflicts(self, feature):
|
||||
# if we have a unique subdivision but no country, use the subdivision's country
|
||||
# this happens in coastal regions when territorial waters overlap in the tile, but
|
||||
# actual land boundaries don't. As we primarily care about correct result on land,
|
||||
# we can ignore the overlap on water
|
||||
if (not feature[1] or len(feature[1]) == 0) and feature[2] and len(feature[2]) == 1:
|
||||
feature[1] = [(feature[2][0][0][:2], 1)]
|
||||
|
||||
# if subdivision country and country code conflict, discard the subdivision
|
||||
# this is mainly a problem for French overseas territories, and there the country
|
||||
# code is actually more useful
|
||||
if feature[1] and len(feature[1]) == 1 and feature[2] and len(feature[2]) == 1 and feature[1][0][0] != feature[2][0][0][:2]:
|
||||
feature[2] = None
|
||||
|
||||
def finished(self, result):
|
||||
if not result and self.exception != None:
|
||||
QgsMessageLog.logMessage('Task "{name}" Exception: {exception}'.format(name=self.description(), exception=self.exception), LOG_CATEGORY, Qgis.Critical)
|
||||
raise self.exception
|
||||
|
||||
#
|
||||
# Task for spawning the sub-tasks doing the actual work, and accumulating the result
|
||||
#
|
||||
class SpatialIndexerTask(QgsTask):
|
||||
def __init__(self, context, loadLayersTask):
|
||||
super().__init__('Compute spatial index', QgsTask.CanCancel)
|
||||
self.context = context
|
||||
self.tasks = []
|
||||
self.conflictTiles = [0, 0, 0]
|
||||
self.startTime = time.time()
|
||||
self.propertyTable = []
|
||||
|
||||
startDepth = 4
|
||||
startIncrement = 1 << (2 * (zDepth - startDepth))
|
||||
for i in range(0, (1 << (2 * startDepth))):
|
||||
task = SpatialIndexerSubTask(context, i * startIncrement, zDepth - startDepth)
|
||||
self.addSubTask(task, [loadLayersTask], QgsTask.ParentDependsOnSubTask)
|
||||
self.tasks.append(task)
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
QgsMessageLog.logMessage('Aggregating results...', LOG_CATEGORY, Qgis.Info)
|
||||
|
||||
# compact the spatial index and prepare the property map
|
||||
spatialIndex = []
|
||||
propertyMap = {}
|
||||
prevProperty = (None, None, None)
|
||||
propertyMap[prevProperty] = 0
|
||||
for task in self.tasks:
|
||||
for (z,res) in task.result:
|
||||
res = self.normalize(res);
|
||||
tmp = []
|
||||
for i in range(len(res)):
|
||||
if res[i] == None or len(res[i]) == 0:
|
||||
tmp.append(None)
|
||||
else:
|
||||
tmp.append(res[i][0][0])
|
||||
if res[i] == None:
|
||||
self.conflictTiles[i] += 1
|
||||
prop = (tmp[0], tmp[1], tmp[2])
|
||||
|
||||
if prevProperty == prop:
|
||||
continue
|
||||
prevProperty = prop
|
||||
spatialIndex.append((z, prop))
|
||||
propertyMap[prop] = 0
|
||||
|
||||
for prop in propertyMap:
|
||||
self.propertyTable.append(prop)
|
||||
self.propertyTable.sort(key = lambda x: (x[0] if x[0] else "", x[1] if x[1] else "", x[2] if x[2] else ""))
|
||||
for i in range(len(self.propertyTable)):
|
||||
propertyMap[self.propertyTable[i]] = i
|
||||
|
||||
# write spatial index
|
||||
out = open('../../data/spatial_index_data.cpp', 'w')
|
||||
out.write("""/*
|
||||
* SPDX-License-Identifier: ODbL-1.0
|
||||
* SPDX-FileCopyrightText: OpenStreetMap contributors
|
||||
*
|
||||
* Autogenerated spatial index generated using QGIS.
|
||||
*/
|
||||
|
||||
#include "spatial_index_entry_p.h"
|
||||
|
||||
static constexpr const SpatialIndexEntry spatial_index[] = {
|
||||
// clang-format off
|
||||
""")
|
||||
prevProperties = (None, None, None)
|
||||
for (z, prop) in spatialIndex:
|
||||
out.write(f" {{{z}, {propertyMap[prop]}}},\n")
|
||||
out.write(" // clang-format on\n};\n")
|
||||
out.close()
|
||||
|
||||
# write property table
|
||||
out = open('../../data/spatial_index_properties.cpp', 'w')
|
||||
out.write("""/*
|
||||
* SPDX-License-Identifier: ODbL-1.0
|
||||
* SPDX-FileCopyrightText: OpenStreetMap contributors
|
||||
*
|
||||
* Autogenerated spatial index generated using QGIS.
|
||||
*/
|
||||
|
||||
#include "spatial_index_property_p.h"
|
||||
#include "timezone_names_p.h"
|
||||
|
||||
static constexpr const SpatialIndexProperty spatial_index_properties[] = {
|
||||
""")
|
||||
for p in self.propertyTable:
|
||||
if not p[1] and not p[2]:
|
||||
out.write(f" {{Tz::{tzIdToEnum(p[0])}}},\n")
|
||||
elif not p[2]:
|
||||
out.write(f" {{Tz::{tzIdToEnum(p[0])}, \"{p[1]}\"}},\n")
|
||||
else:
|
||||
out.write(f" {{Tz::{tzIdToEnum(p[0])}, \"{p[2]}\"}},\n")
|
||||
out.write("};\n")
|
||||
out.close()
|
||||
|
||||
# write zindex parameters
|
||||
out = open('../../data/spatial_index_parameters_p.h', 'w')
|
||||
out.write("""/*
|
||||
* SPDX-License-Identifier: CC0-1.0
|
||||
* SPDX-FileCopyrightText: none
|
||||
*
|
||||
* Autogenerated spatial index generated using QGIS.
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
""")
|
||||
out.write(f"constexpr const float XStart = {xStart};\n")
|
||||
out.write(f"constexpr const float XRange = {xRange};\n")
|
||||
out.write(f"constexpr const float YStart = {yStart};\n")
|
||||
out.write(f"constexpr const float YRange = {yRange};\n")
|
||||
out.write(f"constexpr const uint8_t ZDepth = {zDepth};\n")
|
||||
out.close()
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.exception = e
|
||||
QgsMessageLog.logMessage('Exception in task "{}"'.format(self.exception), LOG_CATEGORY, Qgis.Info)
|
||||
return False
|
||||
|
||||
def normalize(self, feature):
|
||||
# normalization we couldn't do in the sub tasks as they rely on results not available yet at that point
|
||||
# fill in missing timezones from country/subdiv to tz maps
|
||||
# this is needed for the same reason we do the subdivision to country back filling above, conflicts in
|
||||
# territorial waters but a unique result on land
|
||||
tz = None
|
||||
if feature[2] and len(feature[2]) == 1:
|
||||
subdivCode = feature[2][0][0]
|
||||
subdivToTz = self.context['subdivisionToTimezoneMap']
|
||||
if subdivCode in subdivToTz and len(subdivToTz[subdivCode]) == 1:
|
||||
tz = list(subdivToTz[subdivCode])[0]
|
||||
if not tz and feature[1] and len(feature[1]) == 1:
|
||||
countryCode = feature[1][0][0]
|
||||
countryToTz = self.context['countryToTimezoneMap']
|
||||
if countryCode in countryToTz and len(countryToTz[countryCode]) == 1:
|
||||
tz = list(countryToTz[countryCode])[0]
|
||||
if tz:
|
||||
feature[0] = [(tz, 1)]
|
||||
|
||||
return feature
|
||||
|
||||
def finished(self, result):
|
||||
QgsMessageLog.logMessage('Finished task "{}"'.format(self.description()), LOG_CATEGORY, Qgis.Info)
|
||||
tileCount = 1 << (2 * zDepth)
|
||||
for i in range(len(self.conflictTiles)):
|
||||
QgsMessageLog.logMessage(f" {self.conflictTiles[i] / tileCount} of feature {i} area is conflicted", LOG_CATEGORY, Qgis.Info)
|
||||
QgsMessageLog.logMessage(f" collected {len(self.propertyTable)} distinct features", LOG_CATEGORY, Qgis.Info)
|
||||
QgsMessageLog.logMessage(f" computation took {time.time() - self.startTime} seconds", LOG_CATEGORY, Qgis.Info)
|
||||
if not result and self.exception != None:
|
||||
QgsMessageLog.logMessage('Task "{name}" Exception: {exception}'.format(name=self.description(), exception=self.exception), LOG_CATEGORY, Qgis.Critical)
|
||||
raise self.exception
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
# SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
||||
# SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
|
||||
from config import *
|
||||
import io
|
||||
import os
|
||||
from qgis import *
|
||||
from qgis.core import *
|
||||
|
||||
def tzIdToEnum(tzId):
|
||||
return tzId.replace('/', '_').replace('-', '_')
|
||||
|
||||
def normalizedTz(tzId):
|
||||
if tzId in TZID_MAP:
|
||||
return TZID_MAP[tzId]
|
||||
return tzId
|
||||
|
||||
def normalizedCountry(code):
|
||||
if code in ISO3166_1_MAP:
|
||||
return ISO3166_1_MAP[code]
|
||||
return code
|
||||
|
||||
# Generate IANA timezone names string table
|
||||
# This allows us to reference timezones by a uint16_t in other data tables
|
||||
class TimezoneStringTableTask(QgsTask):
|
||||
def __init__(self, context):
|
||||
super().__init__('Generate timezone string table', QgsTask.CanCancel)
|
||||
self.context = context
|
||||
|
||||
def run(self):
|
||||
QgsMessageLog.logMessage('Generating timezone string table', LOG_CATEGORY, Qgis.Info)
|
||||
tzLayer = self.context['tzLayer']
|
||||
tzIds = set()
|
||||
for tz in tzLayer.getFeatures():
|
||||
tzIds.add(tz['tzid'])
|
||||
tzIds = list(tzIds)
|
||||
tzIds.sort()
|
||||
offsets = [0]
|
||||
|
||||
out = open('../../data/timezone_name_table.cpp', 'w')
|
||||
out.write("""/*
|
||||
* SPDX-License-Identifier: ODbL-1.0
|
||||
* SPDX-FileCopyrightText: OpenStreetMap contributors
|
||||
*
|
||||
* Autogenerated using QGIS - do not edit!
|
||||
*/
|
||||
|
||||
static constexpr const char timezone_name_table[] =
|
||||
""")
|
||||
for tzId in tzIds:
|
||||
out.write(f" \"{tzId}\\0\"\n")
|
||||
offsets.append(offsets[-1] + len(tzId) + 1)
|
||||
out.seek(out.tell() - 1, io.SEEK_SET) # to make clang-format happy
|
||||
out.write(";\n")
|
||||
out.close()
|
||||
|
||||
out = open('../../data/timezone_names_p.h', 'w')
|
||||
out.write("""/*
|
||||
* SPDX-License-Identifier: ODbL-1.0
|
||||
* SPDX-FileCopyrightText: OpenStreetMap contributors
|
||||
*
|
||||
* Autogenerated using QGIS - do not edit!
|
||||
*/
|
||||
|
||||
#ifndef TIMEZONE_NAMES_P_H
|
||||
#define TIMEZONE_NAMES_P_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
enum Tz : uint16_t {
|
||||
""")
|
||||
for i in range(len(tzIds)):
|
||||
out.write(f" {tzIdToEnum(tzIds[i])} = {offsets[i]},\n")
|
||||
out.write(f" Undefined = {offsets[-1] - 1},\n") # points to the last null byte
|
||||
out.write("};\n\n#endif\n")
|
||||
out.close()
|
||||
return True
|
||||
|
||||
# Computes country/country subdivision to timezone mapping
|
||||
class RegionToTimezoneMapTask(QgsTask):
|
||||
def __init__(self, context):
|
||||
super().__init__('Computing region to timezone mapping', QgsTask.CanCancel)
|
||||
self.context = context
|
||||
|
||||
def run(self):
|
||||
QgsMessageLog.logMessage('Computing region to timezone mapping', LOG_CATEGORY, Qgis.Info)
|
||||
countryLayer = self.context['countryLayer']
|
||||
tzLayer = self.context['tzLayer']
|
||||
countryToTz = {}
|
||||
for country in countryLayer.getFeatures():
|
||||
countryCode = country['ISO3166-1']
|
||||
if not countryCode in countryToTz:
|
||||
countryToTz[countryCode] = set()
|
||||
countryGeom = country.geometry()
|
||||
countryArea = countryGeom.area()
|
||||
for tz in tzLayer.getFeatures():
|
||||
tzId = normalizedTz(tz['tzId'])
|
||||
if tz.geometry().intersects(countryGeom):
|
||||
# filter out intersection noise along the boundaries
|
||||
area = tz.geometry().intersection(countryGeom).area()
|
||||
tzAreaRatio = area / tz.geometry().area()
|
||||
countryAreaRatio = area / countryArea
|
||||
if tzAreaRatio > 0.01 or countryAreaRatio > 0.1:
|
||||
countryToTz[countryCode].add(tzId)
|
||||
|
||||
out = open('../../data/country_timezone_map.cpp', 'w')
|
||||
out.write("""/*
|
||||
* SPDX-License-Identifier: ODbL-1.0
|
||||
* SPDX-FileCopyrightText: OpenStreetMap contributors
|
||||
*
|
||||
* Autogenerated using QGIS - do not edit!
|
||||
*/
|
||||
|
||||
#include "isocodes_p.h"
|
||||
#include "mapentry_p.h"
|
||||
#include "timezone_names_p.h"
|
||||
|
||||
static constexpr const MapEntry<uint16_t> country_timezone_map[] = {
|
||||
""")
|
||||
countries = list(countryToTz)
|
||||
countries.sort()
|
||||
for country in countries:
|
||||
if len(countryToTz[country]) == 1:
|
||||
out.write(f" {{IsoCodes::alpha2CodeToKey(\"{country}\"), Tz::{tzIdToEnum(list(countryToTz[country])[0])}}},\n")
|
||||
|
||||
out.write("};\n")
|
||||
out.close()
|
||||
|
||||
# for countries with more than one tz, match against subdivisions
|
||||
subdivToTz = {}
|
||||
subdivLayer = self.context['subdivLayer']
|
||||
tzLayer = self.context['tzLayer']
|
||||
for subdiv in subdivLayer.getFeatures():
|
||||
code = subdiv['ISO3166-2']
|
||||
country = code[:2]
|
||||
if len(countryToTz[country]) <= 1:
|
||||
continue
|
||||
if not code in subdivToTz:
|
||||
subdivToTz[code] = {}
|
||||
subdivGeom = subdiv.geometry()
|
||||
subdivArea = subdivGeom.area()
|
||||
for tz in tzLayer.getFeatures():
|
||||
tzId = normalizedTz(tz['tzId'])
|
||||
if tz.geometry().intersects(subdivGeom):
|
||||
# filter out intersection noise along the boundaries
|
||||
area = tz.geometry().intersection(subdivGeom).area()
|
||||
tzAreaRatio = area / tz.geometry().area()
|
||||
subdivAreaRatio = area / subdivArea
|
||||
if tzAreaRatio > 0.01 or subdivAreaRatio > 0.1:
|
||||
if not tzId in subdivToTz[code]:
|
||||
subdivToTz[code][tzId] = area
|
||||
else:
|
||||
subdivToTz[code][tzId] += area
|
||||
|
||||
out = open('../../data/subdivision_timezone_map.cpp', 'w')
|
||||
out.write("""/*
|
||||
* SPDX-License-Identifier: ODbL-1.0
|
||||
* SPDX-FileCopyrightText: OpenStreetMap contributors
|
||||
*
|
||||
* Autogenerated using QGIS - do not edit!
|
||||
*/
|
||||
|
||||
#include "isocodes_p.h"
|
||||
#include "mapentry_p.h"
|
||||
#include "timezone_names_p.h"
|
||||
|
||||
static constexpr const MapEntry<uint32_t> subdivision_timezone_map[] = {
|
||||
""")
|
||||
subdivs = list(subdivToTz)
|
||||
subdivs.sort()
|
||||
for subdiv in subdivs:
|
||||
# sort by area, biggest one first
|
||||
tzs = list(subdivToTz[subdiv])
|
||||
tzs.sort(key = lambda x: subdivToTz[subdiv][x], reverse = True)
|
||||
for tz in tzs:
|
||||
out.write(f" {{IsoCodes::subdivisionCodeToKey(\"{subdiv}\"), Tz::{tzIdToEnum(tz)}}},\n")
|
||||
if len(subdivToTz[subdiv]) == 0:
|
||||
out.write(f" // {subdiv}\n")
|
||||
|
||||
out.write("};\n")
|
||||
out.close()
|
||||
|
||||
self.context['countryToTimezoneMap'] = countryToTz
|
||||
self.context['subdivisionToTimezoneMap'] = subdivToTz
|
||||
return True
|
||||
@@ -0,0 +1,125 @@
|
||||
# SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
||||
# SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
|
||||
# data sources
|
||||
TZDATA_VERSION = '2020d'
|
||||
TZDATA_URL = f"https://github.com/evansiroky/timezone-boundary-builder/releases/download/{TZDATA_VERSION}/timezones.shapefile.zip"
|
||||
ISO3166_1_VERSION = '2021-08-16'
|
||||
ISO3166_1_URL = f"https://volkerkrause.eu/~vkrause/iso3166-boundaries/iso3166-1-boundaries.shp-{ISO3166_1_VERSION}.zip"
|
||||
ISO3166_2_VERSION = ISO3166_1_VERSION
|
||||
ISO3166_2_URL = f"https://volkerkrause.eu/~vkrause/iso3166-boundaries/iso3166-2-boundaries.shp-{ISO3166_2_VERSION}.zip"
|
||||
|
||||
# ISO 3166-1 code mappings
|
||||
# This is for codes that should be unconditionally replaced, which is mainly useful
|
||||
# for certain historical or political corner-cases or "non-countries" like Antarctica
|
||||
ISO3166_1_MAP = {
|
||||
'AQ': None,
|
||||
'AX': 'FI',
|
||||
'SJ': 'NO',
|
||||
'UM': 'US'
|
||||
}
|
||||
|
||||
# ISO 3166-1 overlap disambiguation
|
||||
# This is mainly relevant for oversees territories that both have their own code
|
||||
# as well that of the country they belong to
|
||||
ISO3166_1_DISAMBIGUATION_MAP = {
|
||||
( 'AS', 'US' ),
|
||||
( 'AW', 'NL' ),
|
||||
( 'BL', 'FR' ),
|
||||
( 'BQ', 'NL' ),
|
||||
( 'BT', 'CN' ),
|
||||
( 'CC', 'AU' ),
|
||||
( 'CW', 'NL' ),
|
||||
( 'CX', 'AU' ),
|
||||
( 'GF', 'FR' ),
|
||||
( 'GP', 'FR' ),
|
||||
( 'GU', 'US' ),
|
||||
( 'HK', 'CN' ),
|
||||
( 'HT', 'US' ),
|
||||
( 'MF', 'FR' ),
|
||||
( 'MO', 'CN' ),
|
||||
( 'MP', 'US' ),
|
||||
( 'MQ', 'FR' ),
|
||||
( 'NC', 'FR' ),
|
||||
( 'NF', 'AU' ),
|
||||
( 'PF', 'FR' ),
|
||||
( 'PM', 'FR' ),
|
||||
( 'PR', 'US' ),
|
||||
( 'RE', 'FR' ),
|
||||
( 'SX', 'NL' ),
|
||||
( 'TF', 'FR' ),
|
||||
( 'VI', 'US' ),
|
||||
( 'WF', 'FR' ),
|
||||
( 'YT', 'FR' )
|
||||
}
|
||||
|
||||
# ISO 3166-2 filter configuration
|
||||
# most of those are sub-subdivisions
|
||||
ISO3166_2_FILTER = [
|
||||
{ 'country': 'BD', 'admin_level': 5 },
|
||||
{ 'country': 'BE', 'admin_level': 6 },
|
||||
{ 'country': 'BF', 'admin_level': 5 },
|
||||
{ 'country': 'CZ', 'admin_level': 7 },
|
||||
{ 'country': 'ES', 'admin_level': 6 },
|
||||
{ 'country': 'FR', 'admin_level': 5 },
|
||||
{ 'country': 'FR', 'admin_level': 6 },
|
||||
{ 'country': 'GB', 'admin_level': 6 },
|
||||
{ 'country': 'GB', 'admin_level': 8 },
|
||||
{ 'country': 'GN', 'admin_level': 6 },
|
||||
{ 'country': 'GQ', 'admin_level': 4 },
|
||||
{ 'country': 'GW', 'admin_level': 4 },
|
||||
{ 'country': 'IE', 'admin_level': 6 },
|
||||
{ 'country': 'IE', 'admin_level': 7 },
|
||||
{ 'country': 'IT', 'admin_level': 6 },
|
||||
{ 'country': 'LK', 'admin_level': 5 },
|
||||
{ 'country': 'LT', 'admin_level': 5 },
|
||||
{ 'country': 'MA', 'admin_level': 5 },
|
||||
{ 'country': 'MW', 'admin_level': 4 },
|
||||
{ 'country': 'NP', 'admin_level': 4 },
|
||||
{ 'country': 'NP', 'admin_level': 5 },
|
||||
{ 'country': 'PH', 'admin_level': 4 },
|
||||
{ 'country': 'UG', 'admin_level': 4 }
|
||||
]
|
||||
|
||||
|
||||
# Timezone mapping
|
||||
# use this to replace timezone ids with an equivalent
|
||||
# this is mainly useful for filtering out timezones of limited practical or merely historical relevance,
|
||||
# trading historical accuracy for practical usability for current and future date/time values
|
||||
TZID_MAP = {
|
||||
'America/Argentina/Catamarca': 'America/Argentina/Buenos_Aires',
|
||||
'America/Argentina/Cordoba': 'America/Argentina/Buenos_Aires',
|
||||
'America/Argentina/Jujuy': 'America/Argentina/Buenos_Aires',
|
||||
'America/Argentina/La_Rioja': 'America/Argentina/Buenos_Aires',
|
||||
'America/Argentina/Mendoza': 'America/Argentina/Buenos_Aires',
|
||||
'America/Argentina/Rio_Gallegos': 'America/Argentina/Buenos_Aires',
|
||||
'America/Argentina/Salta': 'America/Argentina/Buenos_Aires',
|
||||
'America/Argentina/San_Juan': 'America/Argentina/Buenos_Aires',
|
||||
'America/Argentina/San_Luis': 'America/Argentina/Buenos_Aires',
|
||||
'America/Argentina/Tucuman': 'America/Argentina/Buenos_Aires',
|
||||
'America/Argentina/Ushuaia': 'America/Argentina/Buenos_Aires',
|
||||
'America/Nipigon': 'America/Toronto',
|
||||
'Arctic/Longyearbyen': 'Europe/Oslo',
|
||||
'Asia/Famagusta': 'Asia/Nicosia',
|
||||
'Asia/Kuching': 'Asia/Kuala_Lumpur',
|
||||
'Europe/Busingen': 'Europe/Berlin',
|
||||
'Europe/Mariehamn': 'Europe/Helsinki'
|
||||
}
|
||||
|
||||
#
|
||||
# parameters for the spatial index
|
||||
#
|
||||
featureAreaRatioThreshold = 0.02 # 1% at zDepth 11 is ~150m
|
||||
zDepth = 11 # minimum tile size is 1/(2^zdepth), amount of bits needed to store z index is 2*zDepth
|
||||
|
||||
# z-order curve coverage parameters
|
||||
xStart = -180
|
||||
xRange = 360
|
||||
# cut out artic regions (starting at 60°S and 80°N), that saves about 23% z-order curve coverage which we
|
||||
# can better use to increase precision in more relevant areas
|
||||
yStart = -60
|
||||
yRange = 140
|
||||
|
||||
|
||||
# constants
|
||||
LOG_CATEGORY = 'KI18n Data Generator'
|
||||
@@ -0,0 +1,34 @@
|
||||
# SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
||||
# SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
|
||||
import os
|
||||
import qgis
|
||||
from LayerTasks import *
|
||||
from SpatialIndexTasks import *
|
||||
from TimezoneTableTasks import *
|
||||
from config import *
|
||||
|
||||
class MainTask(QgsTask):
|
||||
def __init__(self, context):
|
||||
super().__init__('Generating geographic data for KI18N', QgsTask.CanCancel)
|
||||
self.context = context
|
||||
self.loadLayersTask = LoadLayersTask(context)
|
||||
self.addSubTask(self.loadLayersTask, [], QgsTask.ParentDependsOnSubTask)
|
||||
|
||||
self.tzStringTableTask = TimezoneStringTableTask(context)
|
||||
self.addSubTask(self.tzStringTableTask, [self.loadLayersTask], QgsTask.ParentDependsOnSubTask)
|
||||
self.regionToTzMapTask = RegionToTimezoneMapTask(context)
|
||||
self.addSubTask(self.regionToTzMapTask, [self.loadLayersTask], QgsTask.ParentDependsOnSubTask)
|
||||
|
||||
self.spatialIndexTask = SpatialIndexerTask(context, self.loadLayersTask)
|
||||
self.addSubTask(self.spatialIndexTask, [self.loadLayersTask, self.regionToTzMapTask], QgsTask.ParentDependsOnSubTask)
|
||||
|
||||
def run(self):
|
||||
QgsMessageLog.logMessage('Generation completed.', LOG_CATEGORY, Qgis.Info)
|
||||
return True
|
||||
|
||||
# main
|
||||
os.chdir(os.path.join(os.path.dirname(QgsProject.instance().fileName()), 'data'))
|
||||
context = {}
|
||||
task = MainTask(context)
|
||||
QgsApplication.taskManager().addTask(task)
|
||||
@@ -0,0 +1,115 @@
|
||||
<!DOCTYPE qgis PUBLIC 'http://mrcc.com/qgis.dtd' 'SYSTEM'>
|
||||
<qgis version="3.18.0-Zürich">
|
||||
<homePath path=""/>
|
||||
<title></title>
|
||||
<autotransaction active="0"/>
|
||||
<evaluateDefaultValues active="0"/>
|
||||
<trust active="0"/>
|
||||
<projectCrs>
|
||||
<spatialrefsys>
|
||||
<wkt>GEOGCRS["WGS 84",DATUM["World Geodetic System 1984",ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],CS[ellipsoidal,2],AXIS["geodetic latitude (Lat)",north,ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],AXIS["geodetic longitude (Lon)",east,ORDER[2],ANGLEUNIT["degree",0.0174532925199433]],USAGE[SCOPE["Horizontal component of 3D system."],AREA["World."],BBOX[-90,-180,90,180]],ID["EPSG",4326]]</wkt>
|
||||
<proj4>+proj=longlat +datum=WGS84 +no_defs</proj4>
|
||||
<srsid>3452</srsid>
|
||||
<srid>4326</srid>
|
||||
<authid>EPSG:4326</authid>
|
||||
<description>WGS 84</description>
|
||||
<projectionacronym>longlat</projectionacronym>
|
||||
<ellipsoidacronym>EPSG:7030</ellipsoidacronym>
|
||||
<geographicflag>true</geographicflag>
|
||||
</spatialrefsys>
|
||||
</projectCrs>
|
||||
<mapcanvas annotationsVisible="1" name="theMapCanvas">
|
||||
<units>degrees</units>
|
||||
<extent>
|
||||
<xmin>-1</xmin>
|
||||
<ymin>-1</ymin>
|
||||
<xmax>1</xmax>
|
||||
<ymax>1</ymax>
|
||||
</extent>
|
||||
<rotation>0</rotation>
|
||||
<destinationsrs>
|
||||
<spatialrefsys>
|
||||
<wkt>GEOGCRS["WGS 84",DATUM["World Geodetic System 1984",ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],CS[ellipsoidal,2],AXIS["geodetic latitude (Lat)",north,ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],AXIS["geodetic longitude (Lon)",east,ORDER[2],ANGLEUNIT["degree",0.0174532925199433]],USAGE[SCOPE["Horizontal component of 3D system."],AREA["World."],BBOX[-90,-180,90,180]],ID["EPSG",4326]]</wkt>
|
||||
<proj4>+proj=longlat +datum=WGS84 +no_defs</proj4>
|
||||
<srsid>3452</srsid>
|
||||
<srid>4326</srid>
|
||||
<authid>EPSG:4326</authid>
|
||||
<description>WGS 84</description>
|
||||
<projectionacronym>longlat</projectionacronym>
|
||||
<ellipsoidacronym>EPSG:7030</ellipsoidacronym>
|
||||
<geographicflag>true</geographicflag>
|
||||
</spatialrefsys>
|
||||
</destinationsrs>
|
||||
<rendermaptile>0</rendermaptile>
|
||||
<expressionContextScope/>
|
||||
</mapcanvas>
|
||||
<projectModels/>
|
||||
<legend updateDrawingOrder="true"/>
|
||||
<mapViewDocks/>
|
||||
<mapViewDocks3D/>
|
||||
<main-annotation-layer autoRefreshTime="0" refreshOnNotifyEnabled="0" type="annotation" autoRefreshEnabled="0" refreshOnNotifyMessage="">
|
||||
<id>Annotations_41dc69d9_cc28_4177_a7a0_439e8e5129dc</id>
|
||||
<datasource></datasource>
|
||||
<keywordList>
|
||||
<value></value>
|
||||
</keywordList>
|
||||
<layername>Annotations</layername>
|
||||
<srs>
|
||||
<spatialrefsys>
|
||||
<wkt></wkt>
|
||||
<proj4></proj4>
|
||||
<srsid>0</srsid>
|
||||
<srid>0</srid>
|
||||
<authid></authid>
|
||||
<description></description>
|
||||
<projectionacronym></projectionacronym>
|
||||
<ellipsoidacronym></ellipsoidacronym>
|
||||
<geographicflag>true</geographicflag>
|
||||
</spatialrefsys>
|
||||
</srs>
|
||||
<resourceMetadata>
|
||||
<identifier></identifier>
|
||||
<parentidentifier></parentidentifier>
|
||||
<language></language>
|
||||
<type></type>
|
||||
<title></title>
|
||||
<abstract></abstract>
|
||||
<links/>
|
||||
<fees></fees>
|
||||
<encoding></encoding>
|
||||
<crs>
|
||||
<spatialrefsys>
|
||||
<wkt></wkt>
|
||||
<proj4></proj4>
|
||||
<srsid>0</srsid>
|
||||
<srid>0</srid>
|
||||
<authid></authid>
|
||||
<description></description>
|
||||
<projectionacronym></projectionacronym>
|
||||
<ellipsoidacronym></ellipsoidacronym>
|
||||
<geographicflag>true</geographicflag>
|
||||
</spatialrefsys>
|
||||
</crs>
|
||||
<extent/>
|
||||
</resourceMetadata>
|
||||
<items/>
|
||||
<layerOpacity>1</layerOpacity>
|
||||
<blendMode>0</blendMode>
|
||||
</main-annotation-layer>
|
||||
<ProjectViewSettings UseProjectScales="0">
|
||||
<Scales/>
|
||||
<DefaultViewExtent ymin="-1" xmin="-3.3624454148471612" xmax="3.3624454148471612" ymax="1">
|
||||
<spatialrefsys>
|
||||
<wkt>GEOGCRS["WGS 84",DATUM["World Geodetic System 1984",ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],CS[ellipsoidal,2],AXIS["geodetic latitude (Lat)",north,ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],AXIS["geodetic longitude (Lon)",east,ORDER[2],ANGLEUNIT["degree",0.0174532925199433]],USAGE[SCOPE["Horizontal component of 3D system."],AREA["World."],BBOX[-90,-180,90,180]],ID["EPSG",4326]]</wkt>
|
||||
<proj4>+proj=longlat +datum=WGS84 +no_defs</proj4>
|
||||
<srsid>3452</srsid>
|
||||
<srid>4326</srid>
|
||||
<authid>EPSG:4326</authid>
|
||||
<description>WGS 84</description>
|
||||
<projectionacronym>longlat</projectionacronym>
|
||||
<ellipsoidacronym>EPSG:7030</ellipsoidacronym>
|
||||
<geographicflag>true</geographicflag>
|
||||
</spatialrefsys>
|
||||
</DefaultViewExtent>
|
||||
</ProjectViewSettings>
|
||||
</qgis>
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
# SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "data/spatial_index_data.cpp"
|
||||
#include "data/spatial_index_parameters_p.h"
|
||||
#include "data/spatial_index_properties.cpp"
|
||||
#include "spatial_index_p.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
|
||||
constexpr const float XEnd = XStart + XRange;
|
||||
constexpr const float YEnd = YStart + YRange;
|
||||
|
||||
// verify the null entry is first in the property table
|
||||
static_assert(spatial_index_properties[0].m_tz == Tz::Undefined);
|
||||
static_assert(spatial_index_properties[0].m_subdiv == 0);
|
||||
|
||||
// z index conversions
|
||||
constexpr uint32_t latlonToZ(float lat, float lon)
|
||||
{
|
||||
const uint32_t x = ((lon - XStart) / XRange) * (1 << ZDepth);
|
||||
const uint32_t y = ((lat - YStart) / YRange) * (1 << ZDepth);
|
||||
uint32_t z = 0;
|
||||
for (int i = ZDepth - 1; i >= 0; --i) {
|
||||
z <<= 1;
|
||||
z += (y & (1 << i)) ? 1 : 0;
|
||||
z <<= 1;
|
||||
z += (x & (1 << i)) ? 1 : 0;
|
||||
}
|
||||
return z;
|
||||
}
|
||||
|
||||
// "unit tests" for the z index conversion
|
||||
static_assert(latlonToZ(YStart, XStart) == 0);
|
||||
static_assert(latlonToZ(YEnd - 1.0f / (1 << ZDepth), XEnd - 1.0f / (1 << ZDepth)) == (1 << (2 * ZDepth)) - 1);
|
||||
static_assert(latlonToZ(YStart + YRange / 2.0f, 0.0f) == ((1 << (2 * ZDepth - 1)) | (1 << (2 * ZDepth - 2))));
|
||||
|
||||
SpatialIndexProperty SpatialIndex::lookup(float lat, float lon)
|
||||
{
|
||||
if (std::isnan(lat) || std::isnan(lon) || lon < XStart || lon >= XEnd || lat < YStart || lat >= YEnd) {
|
||||
return spatial_index_properties[0];
|
||||
}
|
||||
|
||||
const auto z = latlonToZ(lat, lon);
|
||||
const auto it = std::upper_bound(std::begin(spatial_index), std::end(spatial_index), z);
|
||||
if (it == std::begin(spatial_index)) {
|
||||
return spatial_index_properties[0];
|
||||
}
|
||||
|
||||
return spatial_index_properties[(*std::prev(it)).propertyIndex()];
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "spatial_index_entry_p.h"
|
||||
|
||||
// unit tests for the spatial index entry template
|
||||
static_assert(sizeof(SpatialIndexEntry) == 5);
|
||||
|
||||
static_assert(SpatialIndexEntry(0, 1023).z() == 0);
|
||||
static_assert(SpatialIndexEntry(0, 1023).propertyIndex() == 1023);
|
||||
|
||||
static_assert(SpatialIndexEntry(4194303, 1023).z() == 4194303);
|
||||
static_assert(SpatialIndexEntry(4194303, 1023).propertyIndex() == 1023);
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef SPATIAL_INDEX_ENTRY_P_H
|
||||
#define SPATIAL_INDEX_ENTRY_P_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
|
||||
/** Entry in the spatial index.
|
||||
* This is essentially just a pair of numbers, the first being the position
|
||||
* on the z-order curve and defines the order, the second being the index into the
|
||||
* property table.
|
||||
*
|
||||
* These entries exist in very large quantities, so compact storage is important.
|
||||
*/
|
||||
class SpatialIndexEntry
|
||||
{
|
||||
public:
|
||||
inline constexpr SpatialIndexEntry(uint32_t z, uint32_t propertyIdx)
|
||||
: m_z(z)
|
||||
, m_unused(0)
|
||||
, m_propHigh(propertyIdx >> 8)
|
||||
, m_propLow(propertyIdx)
|
||||
{
|
||||
}
|
||||
|
||||
inline constexpr uint32_t z() const
|
||||
{
|
||||
return m_z;
|
||||
}
|
||||
|
||||
inline constexpr uint32_t propertyIndex() const
|
||||
{
|
||||
return m_propHigh << 8 | m_propLow;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t m_z : 22;
|
||||
[[maybe_unused]] uint32_t m_unused : 6;
|
||||
uint32_t m_propHigh : 4;
|
||||
uint8_t m_propLow;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
inline constexpr bool operator<(SpatialIndexEntry lhs, SpatialIndexEntry rhs)
|
||||
{
|
||||
return lhs.z() < rhs.z();
|
||||
}
|
||||
|
||||
inline constexpr bool operator<(SpatialIndexEntry lhs, uint32_t rhs)
|
||||
{
|
||||
return lhs.z() < rhs;
|
||||
}
|
||||
|
||||
inline constexpr bool operator<(uint32_t lhs, SpatialIndexEntry rhs)
|
||||
{
|
||||
return lhs < rhs.z();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef SPATIALINDEX_H
|
||||
#define SPATIALINDEX_H
|
||||
|
||||
#include "spatial_index_property_p.h"
|
||||
|
||||
/** Spatial index lookup functions . */
|
||||
namespace SpatialIndex
|
||||
{
|
||||
SpatialIndexProperty lookup(float lat, float lon);
|
||||
}
|
||||
|
||||
#endif // SPATIALINDEX_H
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "spatial_index_property_p.h"
|
||||
|
||||
// unit tests for the spatial index property table type
|
||||
static_assert(sizeof(SpatialIndexProperty) == 6);
|
||||
|
||||
// timezone only
|
||||
static_assert(SpatialIndexProperty(Tz::Pacific_Auckland).m_tz == Tz::Pacific_Auckland);
|
||||
static_assert(SpatialIndexProperty(Tz::Pacific_Auckland).m_subdiv == 0);
|
||||
|
||||
// country only
|
||||
static_assert(SpatialIndexProperty(Tz::Europe_Zurich, "CH").m_subdiv > 0);
|
||||
static_assert((SpatialIndexProperty(Tz::Europe_Zurich, "CH").m_subdiv & 0xffff) == 0);
|
||||
|
||||
// subdivision
|
||||
static_assert(SpatialIndexProperty(Tz::Europe_Paris, "FR-IDF").m_subdiv > 0);
|
||||
static_assert((SpatialIndexProperty(Tz::Europe_Paris, "FR-IDF").m_subdiv & 0xffff) > 0);
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef SPATIAL_INDEX_PROPERTY_P_H
|
||||
#define SPATIAL_INDEX_PROPERTY_P_H
|
||||
|
||||
#include "data/timezone_names_p.h"
|
||||
#include "isocodes_p.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
|
||||
/** Entry in the spatial index property table.
|
||||
* That is, this is a set of properties (timezone, country, country subdivision)
|
||||
* associated with a tile in the spatial index, optimized for compact storage.
|
||||
*/
|
||||
class SpatialIndexProperty
|
||||
{
|
||||
public:
|
||||
template<std::size_t N>
|
||||
inline constexpr SpatialIndexProperty(Tz tz, const char (&code)[N])
|
||||
: m_tz(tz)
|
||||
, m_subdiv(N == 3 ? (IsoCodes::alpha2CodeToKey(code, 2) << 16) : IsoCodes::subdivisionCodeToKey(code, N - 1))
|
||||
{
|
||||
}
|
||||
|
||||
inline constexpr SpatialIndexProperty(Tz tz)
|
||||
: m_tz(tz)
|
||||
, m_subdiv(0)
|
||||
{
|
||||
}
|
||||
|
||||
Tz m_tz;
|
||||
uint32_t m_subdiv;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "timezonedata_p.h"
|
||||
|
||||
#include "data/country_timezone_map.cpp"
|
||||
#include "data/subdivision_timezone_map.cpp"
|
||||
#include "data/timezone_name_table.cpp"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
static_assert(isSortedLookupTable(country_timezone_map));
|
||||
static_assert(isSortedLookupTable(subdivision_timezone_map));
|
||||
|
||||
const char *TimezoneData::ianaIdLookup(uint16_t offset)
|
||||
{
|
||||
assert(offset < sizeof(timezone_name_table));
|
||||
return timezone_name_table + offset;
|
||||
}
|
||||
|
||||
const MapEntry<uint16_t> *TimezoneData::countryTimezoneMapBegin()
|
||||
{
|
||||
return std::begin(country_timezone_map);
|
||||
}
|
||||
|
||||
const MapEntry<uint16_t> *TimezoneData::countryTimezoneMapEnd()
|
||||
{
|
||||
return std::end(country_timezone_map);
|
||||
}
|
||||
|
||||
const MapEntry<uint32_t> *TimezoneData::subdivisionTimezoneMapBegin()
|
||||
{
|
||||
return std::begin(subdivision_timezone_map);
|
||||
}
|
||||
|
||||
const MapEntry<uint32_t> *TimezoneData::subdivisionTimezoneMapEnd()
|
||||
{
|
||||
return std::end(subdivision_timezone_map);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef TIMEZONEDATA_P_H
|
||||
#define TIMEZONEDATA_P_H
|
||||
|
||||
#include "mapentry_p.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
/** Utility functions to deal with the compiled-in timezone data. */
|
||||
namespace TimezoneData
|
||||
{
|
||||
const char *ianaIdLookup(uint16_t offset);
|
||||
|
||||
const MapEntry<uint16_t> *countryTimezoneMapBegin();
|
||||
const MapEntry<uint16_t> *countryTimezoneMapEnd();
|
||||
|
||||
const MapEntry<uint32_t> *subdivisionTimezoneMapBegin();
|
||||
const MapEntry<uint32_t> *subdivisionTimezoneMapEnd();
|
||||
|
||||
}
|
||||
|
||||
#endif // TIMEZONEDATA_P_H
|
||||
Reference in New Issue
Block a user