Page MenuHomePhorge

No OneTemporary

diff --git a/kdecore/localization/klocale_kde.cpp b/kdecore/localization/klocale_kde.cpp
index 6cf85f961c..6690f4ad62 100644
--- a/kdecore/localization/klocale_kde.cpp
+++ b/kdecore/localization/klocale_kde.cpp
@@ -1,3138 +1,3144 @@
/* This file is part of the KDE libraries
Copyright (c) 1997,2001 Stephan Kulow <coolo@kde.org>
Copyright (c) 1999 Preston Brown <pbrown@kde.org>
Copyright (c) 1999-2002 Hans Petter Bieker <bieker@kde.org>
Copyright (c) 2002 Lukas Tinkl <lukas@kde.org>
Copyright (C) 2007 Bernhard Loos <nhuh.put@web.de>
Copyright (C) 2009, 2010 John Layt <john@layt.net>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "klocale_p.h"
#include "config-localization.h"
#include <math.h>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef HAVE_TIME_H
#include <time.h>
#endif
#if HAVE_LANGINFO_H
#include <langinfo.h>
#endif
#include <QtCore/QTextCodec>
#include <QtCore/QFile>
#include <QtGui/QPrinter>
#include <QtCore/QFileInfo>
#include <QtCore/QRegExp>
#include <QtCore/QLocale>
#include <QtCore/QHash>
#include <QtCore/QMutexLocker>
#include <QtCore/QStringList>
#include "kcatalog_p.h"
#include "kglobal.h"
#include "kstandarddirs.h"
#include "kconfig.h"
#include "kcomponentdata.h"
#include "kdebug.h"
#include "kdatetime.h"
#include "kcalendarsystem.h"
#include "kcurrencycode.h"
#include "klocalizedstring.h"
#include "kconfiggroup.h"
#include "kcatalogname_p.h"
#include "common_helpers_p.h"
#include "kdayperiod_p.h"
class KLocaleStaticData
{
public:
KLocaleStaticData();
QString maincatalog;
// FIXME: Temporary until full language-sensitivity implemented.
QHash<KLocale::DigitSet, QStringList> languagesUsingDigitSet;
};
KLocaleStaticData::KLocaleStaticData()
{
// Languages using non-Western Arabic digit sets.
// FIXME: Temporary until full language-sensitivity implemented.
languagesUsingDigitSet.insert(KLocale::ArabicIndicDigits, QStringList() << QString::fromLatin1("ar") << QString::fromLatin1("ps"));
languagesUsingDigitSet.insert(KLocale::BengaliDigits, QStringList() << QString::fromLatin1("bn") << QString::fromLatin1("as") );
languagesUsingDigitSet.insert(KLocale::DevenagariDigits, QStringList() << QString::fromLatin1("hi") << QString::fromLatin1("ne"));
languagesUsingDigitSet.insert(KLocale::EasternArabicIndicDigits, QStringList() << QString::fromLatin1("fa") << QString::fromLatin1("ur"));
languagesUsingDigitSet.insert(KLocale::GujaratiDigits, QStringList() << QString::fromLatin1("gu") );
languagesUsingDigitSet.insert(KLocale::GurmukhiDigits, QStringList() << QString::fromLatin1("pa") );
languagesUsingDigitSet.insert(KLocale::KannadaDigits, QStringList() << QString::fromLatin1("kn") );
languagesUsingDigitSet.insert(KLocale::KhmerDigits, QStringList() << QString::fromLatin1("km") );
languagesUsingDigitSet.insert(KLocale::MalayalamDigits, QStringList() << QString::fromLatin1("ml") );
languagesUsingDigitSet.insert(KLocale::OriyaDigits, QStringList() << QString::fromLatin1("or") );
languagesUsingDigitSet.insert(KLocale::TamilDigits, QStringList() << QString::fromLatin1("ta") );
languagesUsingDigitSet.insert(KLocale::TeluguDigits, QStringList() << QString::fromLatin1("te") );
languagesUsingDigitSet.insert(KLocale::ThaiDigits, QStringList() << QString::fromLatin1("th"));
}
K_GLOBAL_STATIC(KLocaleStaticData, staticData)
QDebug operator<<(QDebug debug, const KCatalogName &cn)
{
return debug << cn.name << cn.loadCount;
}
KLocalePrivate::KLocalePrivate(KLocale *q_ptr)
: q(q_ptr),
m_config(KSharedConfig::Ptr()),
m_country(QString()),
m_language(QString()),
m_languages(0),
m_catalogName(QString()),
m_calendar(0),
m_currency(0),
m_codecForEncoding(0)
{
}
KLocalePrivate::KLocalePrivate(const KLocalePrivate &rhs)
{
copy(rhs);
}
KLocalePrivate &KLocalePrivate::operator=(const KLocalePrivate &rhs)
{
copy(rhs);
return *this;
}
KConfig *KLocalePrivate::config()
{
if (m_config != KSharedConfig::Ptr()) {
return m_config.data();
} else {
return KGlobal::config().data();
}
}
void KLocalePrivate::copy(const KLocalePrivate &rhs)
{
// Parent KLocale
q = 0;
// Config
m_config = rhs.m_config;
// Country settings
m_country = rhs.m_country;
m_countryDivisionCode = rhs.m_countryDivisionCode;
// Language settings
m_language = rhs.m_language;
m_languages = 0;
m_languageList = rhs.m_languageList;
m_languageSensitiveDigits = rhs.m_languageSensitiveDigits;
m_nounDeclension = rhs.m_nounDeclension;
// Catalog settings
m_catalogName = rhs.m_catalogName;
m_catalogNames = rhs.m_catalogNames;
m_catalogs = rhs.m_catalogs;
m_numberOfSysCatalogs = rhs.m_numberOfSysCatalogs;
m_useTranscript = rhs.m_useTranscript;
// Calendar settings
m_calendarSystem = rhs.m_calendarSystem;
m_calendar = 0;
m_weekStartDay = rhs.m_weekStartDay;
m_workingWeekStartDay = rhs.m_workingWeekStartDay;
m_workingWeekEndDay = rhs.m_workingWeekEndDay;
m_weekDayOfPray = rhs.m_weekDayOfPray;
// Date/Time settings
m_dateFormat = rhs.m_dateFormat;
m_dateFormatShort = rhs.m_dateFormatShort;
m_timeFormat = rhs.m_timeFormat;
m_dateTimeDigitSet = rhs.m_dateTimeDigitSet;
m_dateMonthNamePossessive = rhs.m_dateMonthNamePossessive;
m_dayPeriods = rhs.m_dayPeriods;
m_weekNumberSystem = rhs.m_weekNumberSystem;
// Number settings
m_decimalPlaces = rhs.m_decimalPlaces;
m_decimalSymbol = rhs.m_decimalSymbol;
m_thousandsSeparator = rhs.m_thousandsSeparator;
m_numericDigitGrouping = rhs.m_numericDigitGrouping;
m_positiveSign = rhs.m_positiveSign;
m_negativeSign = rhs.m_negativeSign;
m_digitSet = rhs.m_digitSet;
// Currency settings
m_currencyCode = rhs.m_currencyCode;
m_currency = 0;
m_currencyCodeList = rhs.m_currencyCodeList;
// Money settings
m_currencySymbol = rhs.m_currencySymbol;
m_monetaryDecimalSymbol = rhs.m_monetaryDecimalSymbol;
m_monetaryThousandsSeparator = rhs.m_monetaryThousandsSeparator;
m_monetaryDigitGrouping = rhs.m_monetaryDigitGrouping;
m_monetaryDecimalPlaces = rhs.m_monetaryDecimalPlaces;
m_positiveMonetarySignPosition = rhs.m_positiveMonetarySignPosition;
m_negativeMonetarySignPosition = rhs.m_negativeMonetarySignPosition;
m_positivePrefixCurrencySymbol = rhs.m_positivePrefixCurrencySymbol;
m_negativePrefixCurrencySymbol = rhs.m_negativePrefixCurrencySymbol;
m_monetaryDigitSet = rhs.m_monetaryDigitSet;
// Units settings
m_binaryUnitDialect = rhs.m_binaryUnitDialect;
m_byteSizeFmt = rhs.m_byteSizeFmt;
m_pageSize = rhs.m_pageSize;
m_measureSystem = rhs.m_measureSystem;
// Encoding settings
m_encoding = rhs.m_encoding;
m_codecForEncoding = rhs.m_codecForEncoding;
m_utf8FileEncoding = rhs.m_utf8FileEncoding;
}
KLocalePrivate::~KLocalePrivate()
{
delete m_currency;
delete m_calendar;
delete m_languages;
}
// init only called from platform specific constructor, so set everything up
// Will be given a persistantConfig or a tempConfig or neither, but never both
void KLocalePrivate::init(const QString& catalogName, const QString &language, const QString &country,
KSharedConfig::Ptr persistantConfig, KConfig *tempConfig)
{
m_catalogName = catalogName;
// Only keep the persistant config if it is not the global
if (persistantConfig != KSharedConfig::Ptr() && persistantConfig != KGlobal::config()) {
m_config = persistantConfig;
}
KConfigGroup cg;
bool useEnvironmentVariables;
// We can't read the formats from the config until we know what locale to read in, but we need
// to read the config to find out the locale. The Country and Language settings should never
// be localized in the config, so we can read a temp copy of them to get us started.
// If no config given, use the global config and include envvars, otherwise use only the config.
if (m_config != KSharedConfig::Ptr()) {
cg = m_config->group(QLatin1String("Locale"));
useEnvironmentVariables = false;
} else if (tempConfig == 0 || tempConfig == KGlobal::config().data()) {
cg = KGlobal::config()->group(QLatin1String("Locale"));
useEnvironmentVariables = true;
} else {
cg = tempConfig->group(QLatin1String("Locale"));
useEnvironmentVariables = false;
}
initEncoding();
initFileNameEncoding();
initCountry(country, cg.readEntry(QLatin1String("Country")));
initLanguageList(language, cg.readEntry(QLatin1String("Language")), useEnvironmentVariables);
// Now that we have a language, we can set up the config which uses it to setLocale()
initConfig(tempConfig);
initMainCatalogs();
initFormat();
}
// Init the config, this is called during construction and by later setCountry/setLanguage calls.
// You _must_ have the m_language set to a valid language or en_US before calling this so a
// setLocale can be applied to the config
void KLocalePrivate::initConfig(KConfig *config)
{
// * If we were constructed with a KSharedConfig it means the user gave it to us
// to use for the life of the KLocale, so just keep using it after a setLocale
// * If passed in KConfig is null or the global config then use the global, but
// do the setLocale first.
// * If we have a KConfig we need to use that, but due to keeping old behaviour
// of not requiring access to it for life we can't keep a reference so instead
// take a copy and use that, but do setLocale first.
if (m_config != KSharedConfig::Ptr()) {
m_config->setLocale(m_language);
} else {
// If no config given then use the global
if (config == 0 || config == KGlobal::config().data()) {
KGlobal::config()->setLocale(m_language);
} else {
config->setLocale(m_language);
m_config = KSharedConfig::openConfig();
config->copyTo(QString(), m_config.data());
m_config->markAsClean();
}
}
}
void KLocalePrivate::initMainCatalogs()
{
KLocaleStaticData *s = staticData;
QMutexLocker lock(kLocaleMutex());
if (!s->maincatalog.isEmpty()) {
// If setMainCatalog was called, then we use that
// (e.g. korgac calls setMainCatalog("korganizer") to use korganizer.po)
m_catalogName = s->maincatalog;
}
if (m_catalogName.isEmpty()) {
kDebug(173) << "KLocale instance created called without valid "
<< "catalog! Give an argument or call setMainCatalog "
<< "before init" << endl;
} else {
// do not use insertCatalog here, that would already trigger updateCatalogs
m_catalogNames.append(KCatalogName(m_catalogName)); // application catalog
// catalogs from which each application can draw translations
const int numberOfCatalogs = m_catalogNames.size();
m_catalogNames.append(KCatalogName(QString::fromLatin1("libphonon")));
m_catalogNames.append(KCatalogName(QString::fromLatin1("kio4")));
m_catalogNames.append(KCatalogName(QString::fromLatin1("kdelibs4")));
m_catalogNames.append(KCatalogName(QString::fromLatin1("kdeqt")));
m_catalogNames.append(KCatalogName(QString::fromLatin1("solid_qt")));
m_catalogNames.append(KCatalogName(QString::fromLatin1("kdecalendarsystems")));
m_numberOfSysCatalogs = m_catalogNames.size() - numberOfCatalogs;
updateCatalogs(); // evaluate this for all languages
}
}
void KLocalePrivate::getLanguagesFromVariable(QStringList &list, const char *variable, bool isLanguageList)
{
QByteArray var(qgetenv(variable));
if (!var.isEmpty()) {
QString value = QFile::decodeName(var);
if (isLanguageList) {
list += value.split(QLatin1Char(':'));
} else {
// Process the value to create possible combinations.
QString lang, ctry, modf, cset;
KLocale::splitLocale(value, lang, ctry, modf, cset);
if (!ctry.isEmpty() && !modf.isEmpty()) {
list += lang + QLatin1Char('_') + ctry + QLatin1Char('@') + modf;
}
// NOTE: The priority is tricky in case both ctry and modf are present.
// Should really lang@modf be of higher priority than lang_ctry?
// For at least one case (Serbian language), it is better this way.
if (!modf.isEmpty()) {
list += lang + QLatin1Char('@') + modf;
}
if (!ctry.isEmpty()) {
list += lang + QLatin1Char('_') + ctry;
}
list += lang;
}
}
}
// init the country at construction only, will ensure we always have a country set
void KLocalePrivate::initCountry(const QString &country, const QString &configCountry)
{
// Cache the valid countries list and add the default C as it is valid to use
QStringList validCountries = allCountriesList();
validCountries.append( defaultCountry() );
// First check if the constructor passed in a value and if so if it is valid
QString putativeCountry = country;
if ( putativeCountry.isEmpty() || !validCountries.contains( putativeCountry, Qt::CaseInsensitive ) ) {
// If the requested country is not valid, try the country as set in the config:
putativeCountry = configCountry;
if ( putativeCountry.isEmpty() || !validCountries.contains( putativeCountry, Qt::CaseInsensitive ) ) {
// If the config country is not valid try the current host system country
putativeCountry = systemCountry();
if ( putativeCountry.isEmpty() || !validCountries.contains( putativeCountry, Qt::CaseInsensitive ) ) {
// Only if no other option, resort to the default C
putativeCountry = defaultCountry();
}
}
}
// Always save as lowercase, unless it's C when we want it uppercase
if ( putativeCountry.toLower() == defaultCountry().toLower() ) {
m_country = defaultCountry();
} else {
m_country = putativeCountry.toLower();
}
}
QString KLocalePrivate::systemCountry() const
{
// Use QLocale for now as it supposedly provides a sensible default most times,
// e.g. if locale is only "de" it is assumed to mean country of "DE"
QString systemCountry, s1, s2, s3;
splitLocale( QLocale::system().name(), s1, systemCountry, s2, s3 );
return systemCountry.toLower();
}
void KLocalePrivate::initLanguageList(const QString &language, const QString &configLanguages,
bool useEnvironmentVariables)
{
m_language = language;
// Collect possible languages by decreasing priority.
// The priority is as follows:
// - the internally set language, if any
// - KDE_LANG environment variable (can be a list)
// - KDE configuration (can be a list)
// - environment variables considered by gettext(3)
// The environment variables are not considered if useEnvironmentVariables is false.
QStringList list;
if (!m_language.isEmpty()) {
list += m_language;
}
// If the Locale object was created with a specific config file, then do not use the
// environmental variables. If the locale object was created with the global config, then
// do use the environmental variables.
if (useEnvironmentVariables) {
// KDE_LANG contains list of language codes, not locale string.
getLanguagesFromVariable(list, "KDE_LANG", true);
}
if (!configLanguages.isEmpty()) {
list += configLanguages.split(QLatin1Char(':'));
}
if (useEnvironmentVariables) {
// Collect languages by same order of priority as for gettext(3).
// LANGUAGE contains list of language codes, not locale string.
getLanguagesFromVariable(list, "LANGUAGE", true);
getLanguagesFromVariable(list, "LC_ALL");
getLanguagesFromVariable(list, "LC_MESSAGES");
getLanguagesFromVariable(list, "LANG");
}
// fall back to the system language
list += systemLanguageList();
// Send the list to filter for really present languages on the system.
setLanguage(list);
}
QStringList KLocalePrivate::systemLanguageList() const
{
return QStringList();
}
void KLocalePrivate::initFormat()
{
KConfigGroup cg(config(), "Locale");
KConfig entryFile(KStandardDirs::locate("locale", QString::fromLatin1("l10n/%1/entry.desktop").arg(m_country)));
entryFile.setLocale(m_language);
KConfigGroup entry(&entryFile, "KCM Locale");
//One-time conversion in 4.4 from FracDigits to DecimalPlaces and MonetaryDecimalPlaces
//If user has personal setting for FracDigits then use it for both Decimal Places
//TODO: Possible to do with kconf_update
if (cg.hasKey("FracDigits")) {
QString fracDigits = cg.readEntry("FracDigits", "");
if (!fracDigits.isEmpty()) {
cg.writeEntry("DecimalPlaces", fracDigits);
cg.writeEntry("MonetaryDecimalPlaces", fracDigits);
}
cg.deleteEntry("FracDigits");
cg.config()->sync();
}
// Numeric
#define readConfigEntry(key, default, save) \
save = entry.readEntry(key, default); \
save = cg.readEntry(key, save);
#define readConfigNumEntry(key, default, save, type) \
save = (type)entry.readEntry(key, int(default)); \
save = (type)cg.readEntry(key, int(save));
// Country settings
readConfigEntry("CountryDivisionCode", QString(), m_countryDivisionCode);
// Numeric formats
readConfigNumEntry("DecimalPlaces", 2, m_decimalPlaces, int);
readConfigEntry("DecimalSymbol", ".", m_decimalSymbol);
readConfigEntry("ThousandsSeparator", ",", m_thousandsSeparator);
m_thousandsSeparator.remove(QString::fromLatin1("$0"));
QString digitGroupFormat;
readConfigEntry("DigitGroupFormat", "3", digitGroupFormat);
m_numericDigitGrouping = digitGroupFormatToList(digitGroupFormat);
readConfigEntry("PositiveSign", "", m_positiveSign);
readConfigEntry("NegativeSign", "-", m_negativeSign);
readConfigNumEntry("DigitSet", KLocale::ArabicDigits, m_digitSet, KLocale::DigitSet);
// FIXME: Temporary until full language-sensitivity implemented.
readConfigEntry("LanguageSensitiveDigits", true, m_languageSensitiveDigits);
// Currency
readConfigEntry("CurrencyCode", "USD", m_currencyCode);
initCurrency();
readConfigEntry("CurrencySymbol", m_currency->defaultSymbol(), m_currencySymbol);
readConfigEntry("CurrencyCodesInUse", QStringList(m_currencyCode), m_currencyCodeList);
// Monetary formats
readConfigNumEntry("MonetaryDecimalPlaces", m_currency->decimalPlaces(), m_monetaryDecimalPlaces, int);
readConfigEntry("MonetaryDecimalSymbol", ".", m_monetaryDecimalSymbol);
readConfigEntry("MonetaryThousandsSeparator", ",", m_monetaryThousandsSeparator);
m_monetaryThousandsSeparator.remove(QString::fromLatin1("$0"));
readConfigEntry("MonetaryDigitGroupFormat", "3", digitGroupFormat);
m_monetaryDigitGrouping = digitGroupFormatToList(digitGroupFormat);
readConfigEntry("PositivePrefixCurrencySymbol", true, m_positivePrefixCurrencySymbol);
readConfigEntry("NegativePrefixCurrencySymbol", true, m_negativePrefixCurrencySymbol);
readConfigNumEntry("PositiveMonetarySignPosition", KLocale::BeforeQuantityMoney,
m_positiveMonetarySignPosition, KLocale::SignPosition);
readConfigNumEntry("NegativeMonetarySignPosition", KLocale::ParensAround,
m_negativeMonetarySignPosition, KLocale::SignPosition);
readConfigNumEntry("MonetaryDigitSet", KLocale::ArabicDigits,
m_monetaryDigitSet, KLocale::DigitSet);
readConfigNumEntry("BinaryUnitDialect", KLocale::IECBinaryDialect,
m_binaryUnitDialect, KLocale::BinaryUnitDialect);
// Date and time
readConfigEntry("TimeFormat", "%H:%M:%S", m_timeFormat);
readConfigEntry("DateFormat", "%A %d %B %Y", m_dateFormat);
readConfigEntry("DateFormatShort", "%Y-%m-%d", m_dateFormatShort);
readConfigNumEntry("WeekStartDay", 1, m_weekStartDay, int); //default to Monday
readConfigNumEntry("WorkingWeekStartDay", 1, m_workingWeekStartDay, int); //default to Monday
readConfigNumEntry("WorkingWeekEndDay", 5, m_workingWeekEndDay, int); //default to Friday
readConfigNumEntry("WeekDayOfPray", 7, m_weekDayOfPray, int); //default to Sunday
readConfigNumEntry("DateTimeDigitSet", KLocale::ArabicDigits,
m_dateTimeDigitSet, KLocale::DigitSet);
readConfigNumEntry("WeekNumberSystem", KLocale::IsoWeekNumber,
m_weekNumberSystem, KLocale::WeekNumberSystem);
// other
#ifndef QT_NO_PRINTER
readConfigNumEntry("PageSize", QPrinter::A4, m_pageSize, QPrinter::PageSize);
#endif
readConfigNumEntry("MeasureSystem", KLocale::Metric, m_measureSystem, KLocale::MeasureSystem);
QString calendarType;
readConfigEntry("CalendarSystem", "gregorian", calendarType);
setCalendar(calendarType);
readConfigEntry("Transcript", true, m_useTranscript);
//Grammatical
//Precedence here is l10n / i18n / config file
KConfig langCfg(KStandardDirs::locate("locale", QString::fromLatin1("%1/entry.desktop").arg(m_language)));
KConfigGroup lang(&langCfg, "KCM Locale");
#define read3ConfigBoolEntry(key, default, save) \
save = entry.readEntry(key, default); \
save = lang.readEntry(key, save); \
save = cg.readEntry(key, save);
read3ConfigBoolEntry("NounDeclension", false, m_nounDeclension);
read3ConfigBoolEntry("DateMonthNamePossessive", false, m_dateMonthNamePossessive);
initDayPeriods(cg);
}
void KLocalePrivate::initDayPeriods(const KConfigGroup &cg)
{
// Prefer any l10n file value for country/language,
// otherwise default to language only value which will be filled in later when i18n available
//Day Period are stored in config as one QStringList entry per Day Period
//PeriodCode,LongName,ShortName,NarrowName,StartTime,EndTime,Offset,OffsetIfZero
//where start and end time are in the format HH:MM:SS.MMM
m_dayPeriods.clear();
QString periodKey = QString::fromLatin1("DayPeriod1");
int i = 1;
while (cg.hasKey(periodKey)) {
QStringList period = cg.readEntry(periodKey, QStringList());
if (period.count() == 8) {
m_dayPeriods.append(KDayPeriod(period[0], period[1], period[2], period[3],
QTime::fromString(period[4], QString::fromLatin1("HH:mm:ss.zzz")),
QTime::fromString(period[5], QString::fromLatin1("HH:mm:ss.zzz")),
period[6].toInt(), period[7].toInt()));
}
i = i + 1;
periodKey = QString::fromLatin1("DayPeriod%1").arg(i);
}
}
bool KLocalePrivate::setCountry(const QString &country, KConfig *newConfig)
{
// Cache the valid countries list and add the default C as it is valid to use
QStringList validCountries = allCountriesList();
validCountries.append(defaultCountry());
QString putativeCountry = country;
if (putativeCountry.isEmpty()) {
// An empty string means to use the system country
putativeCountry = systemCountry();
if (putativeCountry.isEmpty() || !validCountries.contains(putativeCountry, Qt::CaseInsensitive)) {
// If the system country is not valid, use the default
putativeCountry = defaultCountry();
}
} else if (!validCountries.contains(putativeCountry, Qt::CaseInsensitive)) {
return false;
}
// Always save as lowercase, unless it's C when we want it uppercase
if (putativeCountry.toLower() == defaultCountry().toLower()) {
m_country = defaultCountry();
} else {
m_country = putativeCountry.toLower();
}
// Get rid of the old config, start again with the new
m_config = KSharedConfig::Ptr();
initConfig(newConfig);
// Init all the settings
initFormat();
return true;
}
bool KLocalePrivate::setCountryDivisionCode(const QString &countryDivisionCode)
{
m_countryDivisionCode = countryDivisionCode;
return true;
}
bool KLocalePrivate::setLanguage(const QString &language, KConfig *config)
{
QMutexLocker lock(kLocaleMutex());
m_languageList.removeAll(language);
m_languageList.prepend(language); // let us consider this language to be the most important one
m_language = language; // remember main language for shortcut evaluation
// important when called from the outside and harmless when called before
// populating the catalog name list
updateCatalogs();
// Get rid of the old config, start again with the new
m_config = KSharedConfig::Ptr();
initConfig(config);
// Init the new format settings
initFormat();
// Maybe the mo-files for this language are empty, but in principle we can speak all languages
return true;
}
// KDE5 Unlike the other setLanguage call this does not reparse the config so the localized config
// settings for the new primary language will _not_ be loaded. In KDE5 always keep the original
// config so this can be reparsed when required.
bool KLocalePrivate::setLanguage(const QStringList &languages)
{
QMutexLocker lock(kLocaleMutex());
// This list might contain
// 1) some empty strings that we have to eliminate
// 2) duplicate entries like in de:fr:de, where we have to keep the first occurrence of a
// language in order to preserve the order of precenence of the user
// 3) languages into which the application is not translated. For those languages we should not
// even load kdelibs.mo or kio.po. these languages have to be dropped. Otherwise we get
// strange side effects, e.g. with Hebrew: the right/left switch for languages that write
// from right to left (like Hebrew or Arabic) is set in kdelibs.mo. If you only have
// kdelibs.mo but nothing from appname.mo, you get a mostly English app with layout from
// right to left. That was considered to be a bug by the Hebrew translators.
QStringList list;
foreach(const QString &language, languages) {
if (!language.isEmpty() && !list.contains(language) && isApplicationTranslatedInto(language)) {
list.append(language);
}
}
if (!list.contains(KLocale::defaultLanguage())) {
// English should always be added as final possibility; this is important
// for proper initialization of message text post-processors which are
// needed for English too, like semantic to visual formatting, etc.
list.append(KLocale::defaultLanguage());
}
m_language = list.first(); // keep this for shortcut evaluations
m_languageList = list; // keep this new list of languages to use
// important when called from the outside and harmless when called before populating the
// catalog name list
updateCatalogs();
return true; // we found something. Maybe it's only English, but we found something
}
void KLocalePrivate::initCurrency()
{
if (m_currencyCode.isEmpty() || !KCurrencyCode::isValid(m_currencyCode)) {
m_currencyCode = KLocale::defaultCurrencyCode();
}
if (!m_currency || m_currencyCode != m_currency->isoCurrencyCode() || !m_currency->isValid()) {
delete m_currency;
m_currency = new KCurrencyCode(m_currencyCode, m_language);
}
}
void KLocalePrivate::setCurrencyCode(const QString &newCurrencyCode)
{
if (!newCurrencyCode.isEmpty() && newCurrencyCode != m_currency->isoCurrencyCode() &&
KCurrencyCode::isValid(newCurrencyCode)) {
m_currencyCode = newCurrencyCode;
initCurrency();
}
}
bool KLocalePrivate::isApplicationTranslatedInto(const QString &lang)
{
if (lang.isEmpty()) {
return false;
}
if (lang == KLocale::defaultLanguage()) {
// default language is always "installed"
return true;
}
if (m_catalogName.isEmpty()) {
kDebug() << "no appName!";
return false;
}
if (!KCatalog::catalogLocaleDir(m_catalogName, lang).isEmpty()) {
return true;
}
return false;
}
void KLocalePrivate::splitLocale(const QString &aLocale, QString &language, QString &country,
QString &modifier, QString &charset)
{
QString locale = aLocale;
language.clear();
country.clear();
modifier.clear();
charset.clear();
// In case there are several concatenated locale specifications,
// truncate all but first.
int f = locale.indexOf(QLatin1Char(':'));
if (f >= 0) {
locale.truncate(f);
}
f = locale.indexOf(QLatin1Char('.'));
if (f >= 0) {
charset = locale.mid(f + 1);
locale.truncate(f);
}
f = locale.indexOf(QLatin1Char('@'));
if (f >= 0) {
modifier = locale.mid(f + 1);
locale.truncate(f);
}
f = locale.indexOf(QLatin1Char('_'));
if (f >= 0) {
country = locale.mid(f + 1);
locale.truncate(f);
}
language = locale;
}
QString KLocalePrivate::language() const
{
return m_language;
}
QString KLocalePrivate::country() const
{
return m_country;
}
QString KLocalePrivate::countryDivisionCode() const
{
if (m_countryDivisionCode.isEmpty()) {
return country().toUpper();
} else {
return m_countryDivisionCode;
}
}
KCurrencyCode *KLocalePrivate::currency()
{
if (!m_currency) {
initCurrency();
}
return m_currency;
}
QString KLocalePrivate::currencyCode() const
{
return m_currencyCode;
}
void KLocalePrivate::insertCatalog(const QString &catalog)
{
QMutexLocker lock(kLocaleMutex());
int pos = m_catalogNames.indexOf(KCatalogName(catalog));
if (pos != -1) {
++m_catalogNames[pos].loadCount;
return;
}
// Insert new catalog just before system catalogs, to preserve the
// lowest priority of system catalogs.
m_catalogNames.insert(m_catalogNames.size() - m_numberOfSysCatalogs, KCatalogName(catalog));
updateCatalogs(); // evaluate the changed list and generate the necessary KCatalog objects
}
void KLocalePrivate::updateCatalogs()
{
// some changes have occurred. Maybe we have learned or forgotten some languages.
// Maybe the language precedence has changed.
// Maybe we have learned or forgotten some catalog names.
QList<KCatalog> newCatalogs;
// now iterate over all languages and all wanted catalog names and append or create them in the
// right order the sequence must be e.g. nds/appname nds/kdelibs nds/kio de/appname de/kdelibs
// de/kio etc. and not nds/appname de/appname nds/kdelibs de/kdelibs etc. Otherwise we would be
// in trouble with a language sequende nds,<default>,de. In this case <default> must hide
// everything after itself in the language list.
foreach(const QString &lang, m_languageList) {
if (lang == KLocale::defaultLanguage()) {
// Default language has no catalogs (messages from the code),
// so loading catalogs for languages below the default
// would later confuse the fallback resolution.
break;
}
foreach(const KCatalogName &name, m_catalogNames) {
// create and add catalog for this name and language if it exists
if (! KCatalog::catalogLocaleDir(name.name, lang).isEmpty()) {
newCatalogs.append(KCatalog(name.name, lang));
//kDebug(173) << "Catalog: " << name << ":" << lang;
}
}
}
// notify KLocalizedString of catalog update.
m_catalogs = newCatalogs;
KLocalizedString::notifyCatalogsUpdated(m_languageList, m_catalogNames);
}
void KLocalePrivate::removeCatalog(const QString &catalog)
{
QMutexLocker lock(kLocaleMutex());
int pos = m_catalogNames.indexOf(KCatalogName(catalog));
if (pos == -1) {
return;
}
if (--m_catalogNames[pos].loadCount > 0) {
return;
}
m_catalogNames.removeAt(pos);
if (KGlobal::hasMainComponent()) {
// walk through the KCatalog instances and weed out everything we no longer need
updateCatalogs();
}
}
void KLocalePrivate::setActiveCatalog(const QString &catalog)
{
QMutexLocker lock(kLocaleMutex());
int pos = m_catalogNames.indexOf(KCatalogName(catalog));
if (pos == -1) {
return;
}
m_catalogNames.move(pos, 0);
// walk through the KCatalog instances and adapt to the new order
updateCatalogs();
}
void KLocalePrivate::translateRawFrom(const char *catname, const char *msgctxt, const char *msgid, const char *msgid_plural,
unsigned long n, QString *language, QString *translation) const
{
if (!msgid || !msgid[0]) {
kDebug(173) << "KLocale: trying to look up \"\" in catalog. "
<< "Fix the program" << endl;
language->clear();
translation->clear();
return;
}
if (msgctxt && !msgctxt[0]) {
kDebug(173) << "KLocale: trying to use \"\" as context to message. "
<< "Fix the program" << endl;
}
if (msgid_plural && !msgid_plural[0]) {
kDebug(173) << "KLocale: trying to use \"\" as plural message. "
<< "Fix the program" << endl;
}
QMutexLocker locker(kLocaleMutex());
// determine the fallback string
QString fallback;
if (msgid_plural == NULL) {
fallback = QString::fromUtf8(msgid);
} else {
if (n == 1) {
fallback = QString::fromUtf8(msgid);
} else {
fallback = QString::fromUtf8(msgid_plural);
}
}
if (language) {
*language = KLocale::defaultLanguage();
}
if (translation) {
*translation = fallback;
}
// shortcut evaluation if default language is main language: do not consult the catalogs
if (useDefaultLanguage()) {
return;
}
const QList<KCatalog> catalogList = m_catalogs;
QString catNameDecoded;
if (catname != NULL) {
catNameDecoded = QString::fromUtf8(catname);
}
for (QList<KCatalog>::ConstIterator it = catalogList.constBegin(); it != catalogList.constEnd();
++it) {
// shortcut evaluation: once we have arrived at default language, we cannot consult
// the catalog as it will not have an assiciated mo-file. For this default language we can
// immediately pick the fallback string.
if ((*it).language() == KLocale::defaultLanguage()) {
return;
}
if (catNameDecoded.isEmpty() || catNameDecoded == (*it).name()) {
QString text;
if (msgctxt != NULL && msgid_plural != NULL) {
text = (*it).translateStrict(msgctxt, msgid, msgid_plural, n);
} else if (msgid_plural != NULL) {
text = (*it).translateStrict(msgid, msgid_plural, n);
} else if (msgctxt != NULL) {
text = (*it).translateStrict(msgctxt, msgid);
} else {
text = (*it).translateStrict(msgid);
}
if (!text.isEmpty()) {
// we found it
if (language) {
*language = (*it).language();
}
if (translation) {
*translation = text;
}
return;
}
}
}
}
QString KLocalePrivate::translateQt(const char *context, const char *sourceText, const char *comment) const
{
// Qt's context is normally the name of the class of the method which makes
// the tr(sourceText) call. However, it can also be manually supplied via
// translate(context, sourceText) call.
//
// Qt's sourceText is the actual message displayed to the user.
//
// Qt's comment is an optional argument of tr() and translate(), like
// tr(sourceText, comment) and translate(context, sourceText, comment).
//
// We handle this in the following way:
//
// If the comment is given, then it is considered gettext's msgctxt, so a
// context call is made.
//
// If the comment is not given, but context is given, then we treat it as
// msgctxt only if it was manually supplied (the one in translate()) -- but
// we don't know this, so we first try a context call, and if translation
// is not found, we fallback to ordinary call.
//
// If neither comment nor context are given, it's just an ordinary call
// on sourceText.
if (!sourceText || !sourceText[0]) {
kDebug(173) << "KLocale: trying to look up \"\" in catalog. "
<< "Fix the program" << endl;
return QString();
}
if (useDefaultLanguage()) {
return QString();
}
QString translation;
QString language;
// NOTE: Condition (language != defaultLanguage()) means that translation
// was found, otherwise we got the original string back as translation.
if (comment && comment[0]) {
// Comment given, go for context call.
translateRawFrom(0, comment, sourceText, 0, 0, &language, &translation);
} else {
// Comment not given, go for try-fallback with context.
if (context && context[0]) {
translateRawFrom(0, context, sourceText, 0, 0, &language, &translation);
}
if (language.isEmpty() || language == defaultLanguage()) {
translateRawFrom(0, 0, sourceText, 0, 0, &language, &translation);
}
}
if (language != defaultLanguage()) {
return translation;
}
// No proper translation found, return empty according to Qt's expectation.
return QString();
}
QList<KLocale::DigitSet> KLocalePrivate::allDigitSetsList() const
{
QList<KLocale::DigitSet> digitSets;
digitSets.append(KLocale::ArabicDigits);
digitSets.append(KLocale::ArabicIndicDigits);
digitSets.append(KLocale::BengaliDigits);
digitSets.append(KLocale::DevenagariDigits);
digitSets.append(KLocale::EasternArabicIndicDigits);
digitSets.append(KLocale::GujaratiDigits);
digitSets.append(KLocale::GurmukhiDigits);
digitSets.append(KLocale::KannadaDigits);
digitSets.append(KLocale::KhmerDigits);
digitSets.append(KLocale::MalayalamDigits);
digitSets.append(KLocale::OriyaDigits);
digitSets.append(KLocale::TamilDigits);
digitSets.append(KLocale::TeluguDigits);
digitSets.append(KLocale::ThaiDigits);
qSort(digitSets);
return digitSets;
}
QString KLocalePrivate::digitSetString(KLocale::DigitSet digitSet)
{
switch (digitSet) {
case KLocale::ArabicIndicDigits:
return QString::fromUtf8("٠١٢٣٤٥٦٧٨٩");
case KLocale::BengaliDigits:
return QString::fromUtf8("০১২৩৪৫৬৭৮৯");
case KLocale::DevenagariDigits:
return QString::fromUtf8("०१२३४५६७८९");
case KLocale::EasternArabicIndicDigits:
return QString::fromUtf8("۰۱۲۳۴۵۶۷۸۹");
case KLocale::GujaratiDigits:
return QString::fromUtf8("૦૧૨૩૪૫૬૭૮૯");
case KLocale::GurmukhiDigits:
return QString::fromUtf8("੦੧੨੩੪੫੬੭੮੯");
case KLocale::KannadaDigits:
return QString::fromUtf8("೦೧೨೩೪೫೬೭೮೯");
case KLocale::KhmerDigits:
return QString::fromUtf8("០១២៣៤៥៦៧៨៩");
case KLocale::MalayalamDigits:
return QString::fromUtf8("൦൧൨൩൪൫൬൭൮൯");
case KLocale::OriyaDigits:
return QString::fromUtf8("୦୧୨୩୪୫୬୭୮୯");
case KLocale::TamilDigits:
return QString::fromUtf8("௦௧௨௩௪௫௬௭௮");
case KLocale::TeluguDigits:
return QString::fromUtf8("౦౧౨౩౪౫౬౭౯");
case KLocale::ThaiDigits:
return QString::fromUtf8("๐๑๒๓๔๕๖๗๘๙");
default:
return QString::fromUtf8("0123456789");
}
}
QString KLocalePrivate::digitSetToName(KLocale::DigitSet digitSet, bool withDigits) const
{
QString name;
switch (digitSet) {
case KLocale::ArabicIndicDigits:
name = i18nc("digit set", "Arabic-Indic");
break;
case KLocale::BengaliDigits:
name = i18nc("digit set", "Bengali");
break;
case KLocale::DevenagariDigits:
name = i18nc("digit set", "Devanagari");
break;
case KLocale::EasternArabicIndicDigits:
name = i18nc("digit set", "Eastern Arabic-Indic");
break;
case KLocale::GujaratiDigits:
name = i18nc("digit set", "Gujarati");
break;
case KLocale::GurmukhiDigits:
name = i18nc("digit set", "Gurmukhi");
break;
case KLocale::KannadaDigits:
name = i18nc("digit set", "Kannada");
break;
case KLocale::KhmerDigits:
name = i18nc("digit set", "Khmer");
break;
case KLocale::MalayalamDigits:
name = i18nc("digit set", "Malayalam");
break;
case KLocale::OriyaDigits:
name = i18nc("digit set", "Oriya");
break;
case KLocale::TamilDigits:
name = i18nc("digit set", "Tamil");
break;
case KLocale::TeluguDigits:
name = i18nc("digit set", "Telugu");
break;
case KLocale::ThaiDigits:
name = i18nc("digit set", "Thai");
break;
default:
name = i18nc("digit set", "Arabic");
}
if (withDigits) {
QString digits = digitSetString(digitSet);
QString nameWithDigits = i18nc("name of digit set with digit string, "
"e.g. 'Arabic (0123456789)'", "%1 (%2)", name, digits);
return nameWithDigits;
} else {
return name;
}
}
QString KLocalePrivate::convertDigits(const QString &str, KLocale::DigitSet digitSet, bool ignoreContext) const
{
if (!ignoreContext) {
// Fall back to Western Arabic digits if requested digit set
// is not appropriate for current application language.
// FIXME: Temporary until full language-sensitivity implemented.
KLocaleStaticData *s = staticData;
if (m_languageSensitiveDigits && !s->languagesUsingDigitSet[digitSet].contains(m_language)) {
digitSet = KLocale::ArabicDigits;
}
}
QString nstr;
QString digitDraw = digitSetString(digitSet);
foreach(const QChar &c, str) {
if (c.isDigit()) {
nstr += digitDraw[c.digitValue()];
} else {
nstr += c;
}
}
return nstr;
}
QString KLocalePrivate::toArabicDigits(const QString &str)
{
QString nstr;
foreach(const QChar &c, str) {
if (c.isDigit()) {
nstr += QChar('0' + c.digitValue());
} else {
nstr += c;
}
}
return nstr;
}
bool KLocalePrivate::nounDeclension() const
{
return m_nounDeclension;
}
bool KLocalePrivate::dateMonthNamePossessive() const
{
return m_dateMonthNamePossessive;
}
int KLocalePrivate::weekStartDay() const
{
return m_weekStartDay;
}
int KLocalePrivate::workingWeekStartDay() const
{
return m_workingWeekStartDay;
}
int KLocalePrivate::workingWeekEndDay() const
{
return m_workingWeekEndDay;
}
int KLocalePrivate::weekDayOfPray() const
{
return m_weekDayOfPray;
}
int KLocalePrivate::decimalPlaces() const
{
return m_decimalPlaces;
}
QString KLocalePrivate::decimalSymbol() const
{
return m_decimalSymbol;
}
QString KLocalePrivate::thousandsSeparator() const
{
return m_thousandsSeparator;
}
QList<int> KLocalePrivate::numericDigitGrouping() const
{
return m_numericDigitGrouping;
}
QString KLocalePrivate::currencySymbol() const
{
return m_currencySymbol;
}
QString KLocalePrivate::monetaryDecimalSymbol() const
{
return m_monetaryDecimalSymbol;
}
QString KLocalePrivate::monetaryThousandsSeparator() const
{
return m_monetaryThousandsSeparator;
}
QList<int> KLocalePrivate::monetaryDigitGrouping() const
{
return m_monetaryDigitGrouping;
}
QString KLocalePrivate::positiveSign() const
{
return m_positiveSign;
}
QString KLocalePrivate::negativeSign() const
{
return m_negativeSign;
}
/* Just copy to keep the diff looking clean, delete later
int KLocale::fracDigits() const
{
return monetaryDecimalPlaces();
}
*/
int KLocalePrivate::monetaryDecimalPlaces() const
{
return m_monetaryDecimalPlaces;
}
bool KLocalePrivate::positivePrefixCurrencySymbol() const
{
return m_positivePrefixCurrencySymbol;
}
bool KLocalePrivate::negativePrefixCurrencySymbol() const
{
return m_negativePrefixCurrencySymbol;
}
KLocale::SignPosition KLocalePrivate::positiveMonetarySignPosition() const
{
return m_positiveMonetarySignPosition;
}
KLocale::SignPosition KLocalePrivate::negativeMonetarySignPosition() const
{
return m_negativeMonetarySignPosition;
}
static inline void put_it_in(QChar *buffer, int &index, const QString &s)
{
for (int l = 0; l < s.length(); l++) {
buffer[index++] = s.at(l);
}
}
static inline void put_it_in(QChar *buffer, int &index, int number)
{
buffer[index++] = number / 10 + '0';
buffer[index++] = number % 10 + '0';
}
// Convert POSIX Digit Group Format string into a Qlist<int>, e.g. "3;2" converts to (3,2)
QList<int> KLocalePrivate::digitGroupFormatToList(const QString &digitGroupFormat) const
{
QList<int> groupList;
QStringList stringList = digitGroupFormat.split(QLatin1Char(';'));
foreach(const QString &size, stringList) {
groupList.append(size.toInt());
}
return groupList;
}
// Inserts all required occurrences of the group separator into a number string.
QString KLocalePrivate::formatDigitGroup(const QString &number, const QString &groupSeparator, const QString &decimalSeperator, QList<int> groupList) const
{
if (groupList.isEmpty() || groupSeparator.isEmpty()) {
return number;
}
QString num = number;
int groupCount = groupList.count();
int groupAt = 0;
int groupSize = groupList.at(groupAt);
int pos = num.indexOf(decimalSeperator);
if (pos == -1) {
pos = num.length();
}
pos = pos - groupSize;
while (pos > 0 && groupSize > 0) {
num.insert(pos, groupSeparator);
if (groupAt + 1 < groupCount) {
++groupAt;
groupSize = groupList.at(groupAt);
}
pos = pos - groupSize;
}
return num;
}
// Strips all occurrences of the group separator from a number, returns ok if the separators were all in the valid positions
QString KLocalePrivate::parseDigitGroup(const QString &number, const QString &groupSeparator, const QString &decimalSeparator, QList<int> groupList, bool *ok) const
{
QString num = number;
bool valid = true;
if (!groupSeparator.isEmpty()) {
if (!groupList.isEmpty()) {
int separatorSize = groupSeparator.length();
int groupCount = groupList.count();
int groupAt = 0;
int groupSize = groupList.at(groupAt);
int pos = number.indexOf(decimalSeparator);
if (pos == -1) {
pos = number.length();
}
pos = pos - groupSize - separatorSize;
while (pos > 0 && valid && groupSize > 0) {
if (num.mid(pos, separatorSize) == groupSeparator) {
num.remove(pos, separatorSize);
if (groupAt + 1 < groupCount) {
++groupAt;
groupSize = groupList.at(groupAt);
}
pos = pos - groupSize - separatorSize;
} else {
valid = false;
}
}
}
if (num.contains(groupSeparator)) {
valid = false;
num = num.remove(groupSeparator);
}
}
if (ok) {
*ok = valid;
}
return num;
}
QString KLocalePrivate::formatMoney(double num, const QString &symbol, int precision) const
{
// some defaults
QString currencyString = symbol;
if (symbol.isNull()) {
currencyString = currencySymbol();
}
if (precision < 0) {
precision = monetaryDecimalPlaces();
}
// the number itself
bool neg = num < 0;
QString res = QString::number(neg ? -num : num, 'f', precision);
// Replace dot with locale decimal separator
res.replace(QLatin1Char('.'), monetaryDecimalSymbol());
// Insert the thousand separators
res = formatDigitGroup(res, monetaryThousandsSeparator(), monetaryDecimalSymbol(), monetaryDigitGrouping());
// set some variables we need later
int signpos = neg
? negativeMonetarySignPosition()
: positiveMonetarySignPosition();
QString sign = neg
? negativeSign()
: positiveSign();
switch (signpos) {
case KLocale::ParensAround:
res.prepend(QLatin1Char('('));
res.append(QLatin1Char(')'));
break;
case KLocale::BeforeQuantityMoney:
res.prepend(sign);
break;
case KLocale::AfterQuantityMoney:
res.append(sign);
break;
case KLocale::BeforeMoney:
currencyString.prepend(sign);
break;
case KLocale::AfterMoney:
currencyString.append(sign);
break;
}
if (neg ? negativePrefixCurrencySymbol() :
positivePrefixCurrencySymbol()) {
res.prepend(QLatin1Char(' '));
res.prepend(currencyString);
} else {
res.append(QLatin1Char(' '));
res.append(currencyString);
}
// Convert to target digit set.
res = convertDigits(res, m_monetaryDigitSet);
return res;
}
QString KLocalePrivate::formatNumber(double num, int precision) const
{
if (precision < 0) {
precision = decimalPlaces();
}
// no need to round since QString::number does this for us
return formatNumber(QString::number(num, 'f', precision), false, 0);
}
QString KLocalePrivate::formatLong(long num) const
{
return formatNumber((double)num, 0);
}
// increase the digit at 'position' by one
static void _inc_by_one(QString &str, int position)
{
for (int i = position; i >= 0; i--) {
char last_char = str[i].toLatin1();
switch (last_char) {
case '0':
str[i] = '1';
break;
case '1':
str[i] = '2';
break;
case '2':
str[i] = '3';
break;
case '3':
str[i] = '4';
break;
case '4':
str[i] = '5';
break;
case '5':
str[i] = '6';
break;
case '6':
str[i] = '7';
break;
case '7':
str[i] = '8';
break;
case '8':
str[i] = '9';
break;
case '9':
str[i] = '0';
if (i == 0) str.prepend(QLatin1Char('1'));
continue;
case '.':
continue;
}
break;
}
}
// Cut off if more digits in fractional part than 'precision'
static void _round(QString &str, int precision)
{
int decimalSymbolPos = str.indexOf(QLatin1Char('.'));
if (decimalSymbolPos == -1) {
if (precision == 0) return;
else if (precision > 0) { // add dot if missing (and needed)
str.append(QLatin1Char('.'));
decimalSymbolPos = str.length() - 1;
}
}
// fill up with more than enough zeroes (in case fractional part too short)
str.reserve(str.length() + precision);
for (int i = 0; i < precision; ++i)
str.append(QLatin1Char('0'));
// Now decide whether to round up or down
char last_char = str[decimalSymbolPos + precision + 1].toLatin1();
switch (last_char) {
case '0':
case '1':
case '2':
case '3':
case '4':
// nothing to do, rounding down
break;
case '5':
case '6':
case '7':
case '8':
case '9':
_inc_by_one(str, decimalSymbolPos + precision);
break;
default:
break;
}
decimalSymbolPos = str.indexOf(QLatin1Char('.'));
str.truncate(decimalSymbolPos + precision + 1);
// if precision == 0 delete also '.'
if (precision == 0) {
str = str.left(decimalSymbolPos);
}
str.squeeze();
}
QString KLocalePrivate::formatNumber(const QString &numStr, bool round, int precision) const
{
QString tmpString = numStr;
if (precision < 0) {
precision = decimalPlaces();
}
// Skip the sign (for now)
const bool neg = (tmpString[0] == QLatin1Char('-'));
if (neg || tmpString[0] == QLatin1Char('+')) {
tmpString.remove(0, 1);
}
//kDebug(173)<<"tmpString:"<<tmpString;
// Split off exponential part (including 'e'-symbol)
const int expPos = tmpString.indexOf(QLatin1Char('e')); // -1 if not found
QString mantString = tmpString.left(expPos); // entire string if no 'e' found
QString expString;
if (expPos > -1) {
expString = tmpString.mid(expPos); // includes the 'e', or empty if no 'e'
if (expString.length() == 1) {
expString.clear();
}
}
//kDebug(173)<<"mantString:"<<mantString;
//kDebug(173)<<"expString:"<<expString;
if (mantString.isEmpty() || !mantString[0].isDigit()) {// invalid number
mantString = QLatin1Char('0');
}
if (round) {
_round(mantString, precision);
}
// Replace dot with locale decimal separator
mantString.replace(QLatin1Char('.'), decimalSymbol());
// Insert the thousand separators
mantString = formatDigitGroup(mantString, thousandsSeparator(), decimalSymbol(), numericDigitGrouping());
// How can we know where we should put the sign?
mantString.prepend(neg ? negativeSign() : positiveSign());
// Convert to target digit set.
if (digitSet() != KLocale::ArabicDigits) {
mantString = convertDigits(mantString, digitSet());
expString = convertDigits(expString, digitSet());
}
return mantString + expString;
}
// Returns a list of already translated units to use later in formatByteSize
// and friends. Account for every unit in KLocale::BinarySizeUnits
QList<QString> KLocalePrivate::dialectUnitsList(KLocale::BinaryUnitDialect dialect)
{
QList<QString> binaryUnits;
QString s; // Used in CACHE_BYTE_FMT macro defined shortly
// Adds a given translation to the binaryUnits list.
#define CACHE_BYTE_FMT(ctxt_text) \
translateRawFrom(0, ctxt_text, 0, 0, 0, &s); \
binaryUnits.append(s);
// Do not remove i18n: comments below, they are used by the
// translators.
// This prefix is shared by all current dialects.
// i18n: Dumb message, avoid any markup or scripting.
CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("size in bytes", "%1 B"));
switch (dialect) {
case KLocale::MetricBinaryDialect:
// i18n: Dumb message, avoid any markup or scripting.
CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("size in 1000 bytes", "%1 kB"));
// i18n: Dumb message, avoid any markup or scripting.
CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("size in 10^6 bytes", "%1 MB"));
// i18n: Dumb message, avoid any markup or scripting.
CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("size in 10^9 bytes", "%1 GB"));
// i18n: Dumb message, avoid any markup or scripting.
CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("size in 10^12 bytes", "%1 TB"));
// i18n: Dumb message, avoid any markup or scripting.
CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("size in 10^15 bytes", "%1 PB"));
// i18n: Dumb message, avoid any markup or scripting.
CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("size in 10^18 bytes", "%1 EB"));
// i18n: Dumb message, avoid any markup or scripting.
CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("size in 10^21 bytes", "%1 ZB"));
// i18n: Dumb message, avoid any markup or scripting.
CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("size in 10^24 bytes", "%1 YB"));
break;
case KLocale::JEDECBinaryDialect:
// i18n: Dumb message, avoid any markup or scripting.
CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("memory size in 1024 bytes", "%1 KB"));
// i18n: Dumb message, avoid any markup or scripting.
CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("memory size in 2^20 bytes", "%1 MB"));
// i18n: Dumb message, avoid any markup or scripting.
CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("memory size in 2^30 bytes", "%1 GB"));
// i18n: Dumb message, avoid any markup or scripting.
CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("memory size in 2^40 bytes", "%1 TB"));
// i18n: Dumb message, avoid any markup or scripting.
CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("memory size in 2^50 bytes", "%1 PB"));
// i18n: Dumb message, avoid any markup or scripting.
CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("memory size in 2^60 bytes", "%1 EB"));
// i18n: Dumb message, avoid any markup or scripting.
CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("memory size in 2^70 bytes", "%1 ZB"));
// i18n: Dumb message, avoid any markup or scripting.
CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("memory size in 2^80 bytes", "%1 YB"));
break;
case KLocale::IECBinaryDialect:
default:
// i18n: Dumb message, avoid any markup or scripting.
CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("size in 1024 bytes", "%1 KiB"));
// i18n: Dumb message, avoid any markup or scripting.
CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("size in 2^20 bytes", "%1 MiB"));
// i18n: Dumb message, avoid any markup or scripting.
CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("size in 2^30 bytes", "%1 GiB"));
// i18n: Dumb message, avoid any markup or scripting.
CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("size in 2^40 bytes", "%1 TiB"));
// i18n: Dumb message, avoid any markup or scripting.
CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("size in 2^50 bytes", "%1 PiB"));
// i18n: Dumb message, avoid any markup or scripting.
CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("size in 2^60 bytes", "%1 EiB"));
// i18n: Dumb message, avoid any markup or scripting.
CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("size in 2^70 bytes", "%1 ZiB"));
// i18n: Dumb message, avoid any markup or scripting.
CACHE_BYTE_FMT(I18N_NOOP2_NOSTRIP("size in 2^80 bytes", "%1 YiB"));
break;
}
return binaryUnits;
}
QString KLocalePrivate::formatByteSize(double size, int precision, KLocale::BinaryUnitDialect dialect,
KLocale::BinarySizeUnits specificUnit)
{
// Error checking
if (dialect <= KLocale::DefaultBinaryDialect || dialect > KLocale::LastBinaryDialect) {
dialect = m_binaryUnitDialect;
}
if (specificUnit < KLocale::DefaultBinaryUnits || specificUnit > KLocale::UnitLastUnit) {
specificUnit = KLocale::DefaultBinaryUnits;
}
// Choose appropriate units.
QList<QString> dialectUnits;
if (dialect == m_binaryUnitDialect) {
// Cache default units for speed
if (m_byteSizeFmt.size() == 0) {
QMutexLocker lock(kLocaleMutex());
// We only cache the user's default dialect.
m_byteSizeFmt = dialectUnitsList(m_binaryUnitDialect);
}
dialectUnits = m_byteSizeFmt;
} else {
dialectUnits = dialectUnitsList(dialect);
}
int unit = 0; // Selects what unit to use from cached list
double multiplier = 1024.0;
if (dialect == KLocale::MetricBinaryDialect) {
multiplier = 1000.0;
}
// If a specific unit conversion is given, use it directly. Otherwise
// search until the result is in [0, multiplier) (or out of our range).
if (specificUnit == KLocale::DefaultBinaryUnits) {
while (size >= multiplier && unit < (int) KLocale::UnitYottaByte) {
size /= multiplier;
unit++;
}
} else {
// A specific unit is in use
unit = static_cast<int>(specificUnit);
if (unit > 0) {
size /= pow(multiplier, unit);
}
}
if (unit == 0) {
// Bytes, no rounding
return dialectUnits[unit].arg(formatNumber(size, 0));
}
return dialectUnits[unit].arg(formatNumber(size, precision));
}
QString KLocalePrivate::formatByteSize(double size)
{
return formatByteSize(size, 1);
}
KLocale::BinaryUnitDialect KLocalePrivate::binaryUnitDialect() const
{
return m_binaryUnitDialect;
}
void KLocalePrivate::setBinaryUnitDialect(KLocale::BinaryUnitDialect newDialect)
{
if (newDialect > KLocale::DefaultBinaryDialect && newDialect <= KLocale::LastBinaryDialect) {
QMutexLocker lock(kLocaleMutex());
m_binaryUnitDialect = newDialect;
m_byteSizeFmt.clear(); // Reset cached translations.
}
}
QString KLocalePrivate::formatDuration(unsigned long mSec) const
{
if (mSec >= 24*3600000) {
return i18nc("@item:intext %1 is a real number, e.g. 1.23 days", "%1 days",
formatNumber(mSec / (24 * 3600000.0), 2));
} else if (mSec >= 3600000) {
return i18nc("@item:intext %1 is a real number, e.g. 1.23 hours", "%1 hours",
formatNumber(mSec / 3600000.0, 2));
} else if (mSec >= 60000) {
return i18nc("@item:intext %1 is a real number, e.g. 1.23 minutes", "%1 minutes",
formatNumber(mSec / 60000.0, 2));
} else if (mSec >= 1000) {
return i18nc("@item:intext %1 is a real number, e.g. 1.23 seconds", "%1 seconds",
formatNumber(mSec / 1000.0, 2));
}
return i18ncp("@item:intext", "%1 millisecond", "%1 milliseconds", mSec);
}
QString KLocalePrivate::formatSingleDuration(KLocalePrivate::DurationType durationType, int n)
{
switch (durationType) {
case KLocalePrivate::DaysDurationType:
return i18ncp("@item:intext", "1 day", "%1 days", n);
case KLocalePrivate::HoursDurationType:
return i18ncp("@item:intext", "1 hour", "%1 hours", n);
case KLocalePrivate::MinutesDurationType:
return i18ncp("@item:intext", "1 minute", "%1 minutes", n);
case KLocalePrivate::SecondsDurationType:
return i18ncp("@item:intext", "1 second", "%1 seconds", n);
}
return QString();
}
QString KLocalePrivate::prettyFormatDuration(unsigned long mSec) const
{
unsigned long ms = mSec;
int days = ms / (24 * 3600000);
ms = ms % (24 * 3600000);
int hours = ms / 3600000;
ms = ms % 3600000;
int minutes = ms / 60000;
ms = ms % 60000;
int seconds = qRound(ms / 1000.0);
// Handle correctly problematic case #1 (look at KLocaleTest::prettyFormatDuration()
// at klocaletest.cpp)
if (seconds == 60) {
return prettyFormatDuration(mSec - ms + 60000);
}
if (days && hours) {
return i18nc("@item:intext days and hours. This uses the previous item:intext messages. If this does not fit the grammar of your language please contact the i18n team to solve the problem",
"%1 and %2", formatSingleDuration(KLocalePrivate::DaysDurationType, days),
formatSingleDuration(KLocalePrivate::HoursDurationType, hours));
} else if (days) {
return formatSingleDuration(KLocalePrivate::DaysDurationType, days);
} else if (hours && minutes) {
return i18nc("@item:intext hours and minutes. This uses the previous item:intext messages. If this does not fit the grammar of your language please contact the i18n team to solve the problem",
"%1 and %2",
formatSingleDuration(KLocalePrivate::HoursDurationType, hours),
formatSingleDuration(KLocalePrivate::MinutesDurationType, minutes));
} else if (hours) {
return formatSingleDuration(KLocalePrivate::HoursDurationType, hours);
} else if (minutes && seconds) {
return i18nc("@item:intext minutes and seconds. This uses the previous item:intext messages. If this does not fit the grammar of your language please contact the i18n team to solve the problem",
"%1 and %2",
formatSingleDuration(KLocalePrivate::MinutesDurationType, minutes),
formatSingleDuration(KLocalePrivate::SecondsDurationType, seconds));
} else if (minutes) {
return formatSingleDuration(KLocalePrivate::MinutesDurationType, minutes);
} else {
return formatSingleDuration(KLocalePrivate::SecondsDurationType, seconds);
}
}
QString KLocalePrivate::formatDate(const QDate &date, KLocale::DateFormat format)
{
return calendar()->formatDate(date, format);
}
void KLocalePrivate::setMainCatalog(const char *catalog)
{
KLocaleStaticData *s = staticData;
s->maincatalog = QString::fromUtf8(catalog);
}
double KLocalePrivate::readNumber(const QString &_str, bool * ok) const
{
QString str = _str.trimmed();
bool neg = false;
// Check negative or positive signs
// Assumes blank sign is positive even if pos sign set, unless already taken by negative
if (!negativeSign().isEmpty() && str.indexOf(negativeSign()) == 0) {
neg = true;
str.remove(0, negativeSign().length());
str = str.trimmed();
} else if (!positiveSign().isEmpty() && str.indexOf(positiveSign()) == 0) {
neg = false;
str.remove(0, positiveSign().length());
str = str.trimmed();
} else if (negativeSign().isEmpty() && str[0].isDigit()) {
neg = true;
}
/* will hold the scientific notation portion of the number.
Example, with 2.34E+23, exponentialPart == "E+23"
*/
QString exponentialPart;
int EPos;
EPos = str.indexOf(QLatin1Char('E'), 0, Qt::CaseInsensitive);
if (EPos != -1) {
exponentialPart = str.mid(EPos);
str = str.left(EPos);
str = str.trimmed();
}
// Remove group separators
bool groupOk = true;
- str = parseDigitGroup(str, thousandsSeparator(), decimalSymbol(), numericDigitGrouping(), &groupOk);
+ if(str.contains(thousandsSeparator())) {
+ str = parseDigitGroup(str, thousandsSeparator(), decimalSymbol(),
+ numericDigitGrouping(), &groupOk);
+ }
if (!groupOk) {
if (ok) {
*ok = false;
}
return 0.0;
}
int pos = str.indexOf(decimalSymbol());
QString major;
QString minor;
if (pos == -1) {
major = str;
} else {
major = str.left(pos);
minor = str.mid(pos + decimalSymbol().length());
}
// Check the major and minor parts are only digits
bool digitTest = true;
foreach (const QChar &ch, major) {
if (!ch.isDigit()) {
digitTest = false;
break;
}
}
foreach (const QChar &ch, minor) {
if (!ch.isDigit()) {
digitTest = false;
break;
}
}
if (!digitTest) {
if (ok) {
*ok = false;
}
return 0.0;
}
QString tot;
if (neg) {
tot = QLatin1Char('-');
}
tot += major + QLatin1Char('.') + minor + exponentialPart;
tot = toArabicDigits(tot);
return tot.toDouble(ok);
}
double KLocalePrivate::readMoney(const QString &_str, bool *ok) const
{
QString str = _str.trimmed();
bool neg = false;
bool currencyFound = false;
QString symbol = currencySymbol();
// First try removing currency symbol from either end
int pos = str.indexOf(symbol);
if (pos == 0 || pos == (int) str.length() - symbol.length()) {
str.remove(pos, symbol.length());
str = str.trimmed();
currencyFound = true;
}
if (str.isEmpty()) {
if (ok) {
*ok = false;
}
return 0;
}
// Then try removing sign from either end (with a special case for parenthesis)
if (str[0] == QLatin1Char('(') && str[str.length()-1] == QLatin1Char(')')) {
if (positiveMonetarySignPosition() != KLocale::ParensAround) {
neg = true;
}
str.remove(str.length() - 1, 1);
str.remove(0, 1);
str = str.trimmed();
} else {
int len = 0;
QString sign;
int negLen = negativeSign().length();
QString negSign = negativeSign();
if (!negSign.isEmpty() && (str.left(negLen) == negSign || str.right(negSign.length()) == negSign)) {
neg = true;
len = negLen;
sign = negSign;
} else {
int posLen = positiveSign().length();
QString posSign = positiveSign();
if (!posSign.isEmpty() && (str.left(posLen) == posSign || str.right(posSign.length()) == posSign)) {
len = posLen;
sign = posSign;
} else if (negSign.isEmpty() && str[0].isDigit() && str[str.length() - 1].isDigit()){
neg = true;
}
}
if (!sign.isEmpty()) {
if (str.left(len) == sign) {
str.remove(0, len);
} else {
str.remove(str.length() - len, len);
}
str = str.trimmed();
}
}
// Finally try again for the currency symbol, if we didn't find
// it already (because of the negative sign being in the way).
if (!currencyFound) {
pos = str.indexOf(symbol);
if (pos == 0 || pos == (int) str.length() - symbol.length()) {
str.remove(pos, symbol.length());
str = str.trimmed();
}
}
// Remove group separators
bool groupOk = true;
- str = parseDigitGroup(str, monetaryThousandsSeparator(), monetaryDecimalSymbol(), monetaryDigitGrouping(), &groupOk);
+ if(str.contains(monetaryThousandsSeparator())) {
+ str = parseDigitGroup(str, monetaryThousandsSeparator(), monetaryDecimalSymbol(),
+ monetaryDigitGrouping(), &groupOk);
+ }
if (!groupOk) {
if (ok) {
*ok = false;
}
return 0.0;
}
// And parse the rest as a number
pos = str.indexOf(monetaryDecimalSymbol());
QString major;
QString minor;
if (pos == -1) {
major = str;
} else {
major = str.left(pos);
minor = str.mid(pos + monetaryDecimalSymbol().length());
}
// Check the major and minor parts are only digits
bool digitTest = true;
foreach (const QChar &ch, major) {
if (!ch.isDigit()) {
digitTest = false;
break;
}
}
foreach (const QChar &ch, minor) {
if (!ch.isDigit()) {
digitTest = false;
break;
}
}
if (!digitTest) {
if (ok) {
*ok = false;
}
return 0.0;
}
QString tot;
if (neg) {
tot = QLatin1Char('-');
}
tot += major + QLatin1Char('.') + minor;
tot = toArabicDigits(tot);
return tot.toDouble(ok);
}
/**
* helper function to read integers
* @param str
* @param pos the position to start at. It will be updated when we parse it.
* @return the integer read in the string, or -1 if no string
*/
static int readInt(const QString &str, int &pos)
{
if (!str.at(pos).isDigit()) {
return -1;
}
int result = 0;
for (; str.length() > pos && str.at(pos).isDigit(); ++pos) {
result *= 10;
result += str.at(pos).digitValue();
}
return result;
}
QDate KLocalePrivate::readDate(const QString &intstr, bool *ok)
{
return calendar()->readDate(intstr, ok);
}
QDate KLocalePrivate::readDate(const QString &intstr, KLocale::ReadDateFlags flags, bool *ok)
{
return calendar()->readDate(intstr, flags, ok);
}
QDate KLocalePrivate::readDate(const QString &intstr, const QString &fmt, bool *ok)
{
return calendar()->readDate(intstr, fmt, ok);
}
QTime KLocalePrivate::readTime(const QString &intstr, bool *ok) const
{
QTime time = readLocaleTime(intstr, ok, KLocale::TimeDefault, KLocale::ProcessStrict);
if (time.isValid()) {
return time;
}
return readLocaleTime(intstr, ok, KLocale::TimeWithoutSeconds, KLocale::ProcessStrict);
}
QTime KLocalePrivate::readTime(const QString &intstr, KLocale::ReadTimeFlags flags, bool *ok) const
{
return readLocaleTime(intstr, ok, (flags == KLocale::WithSeconds) ? KLocale::TimeDefault : KLocale::TimeWithoutSeconds,
KLocale::ProcessStrict);
}
// remove the first occurrence of the 2-character string
// strip2char from inout and if found, also remove one preceding
// punctuation character and arbitrary number of spaces.
static void stripStringAndPreceedingSeparator(QString &inout, const QLatin1String &strip2char)
{
int remPos = inout.indexOf(strip2char);
if (remPos == -1) {
return;
}
int endPos = remPos + 2;
int curPos = remPos - 1;
while (curPos >= 0 && inout.at(curPos).isSpace()) {
curPos--;
}
// remove the separator sign before the seconds
// and assume that works everywhere
if (curPos >= 0 && inout.at(curPos).isPunct() && inout.at(curPos) != QLatin1Char('%')) {
curPos--;
}
while (curPos >= 0 && inout.at(curPos).isSpace()) {
curPos--;
}
remPos = qMax(curPos + 1, 0);
inout.remove(remPos, endPos - remPos);
}
// remove the first occurrence of the 2-character string
// strip2char from inout and if found, also remove one
// succeeding punctuation character and arbitrary number of spaces.
static void stripStringAndSucceedingSeparator(QString &inout, const QLatin1String &strip2char)
{
int remPos = inout.indexOf(strip2char);
if (remPos == -1) {
return;
}
int curPos = remPos + 2;
while (curPos < inout.size() &&
(inout.at(curPos).isSpace() ||
(inout.at(curPos).isPunct() && inout.at(curPos) != QLatin1Char('%')))) {
curPos++;
}
inout.remove(remPos, curPos - remPos);
}
// remove the first occurrence of "%p" from the inout.
static void stripAmPmFormat(QString &inout)
{
// NOTE: this function assumes that %p - if it's present -
// is either the first or the last element of the format
// string. Either a succeeding or a preceding
// punctuation symbol is stripped.
int length = inout.size();
int ppos = inout.indexOf(QLatin1String("%p"));
if (ppos == -1) {
return;
} else if (ppos == 0) {
// first element, eat succeeding punctuation and spaces
ppos = 2;
while (ppos < length && (inout.at(ppos).isSpace() || inout.at(ppos).isPunct()) &&
inout.at(ppos) != QLatin1Char('%')) {
ppos++;
}
inout = inout.mid(ppos);
} else {
stripStringAndPreceedingSeparator(inout, QLatin1String("%p"));
}
}
QTime KLocalePrivate::readLocaleTime(const QString &intstr, bool *ok, KLocale::TimeFormatOptions options,
KLocale::TimeProcessingOptions processing) const
{
QString str(intstr.simplified().toLower());
QString format(timeFormat().simplified());
int hour = -1;
int minute = -1;
int second = -1;
bool useDayPeriod = false;
KDayPeriod dayPeriod = dayPeriodForTime(QTime(0,0,0));
int strpos = 0;
int formatpos = 0;
bool error = false;
bool excludeSecs = ((options & KLocale::TimeWithoutSeconds) == KLocale::TimeWithoutSeconds);
bool isDuration = ((options & KLocale::TimeDuration) == KLocale::TimeDuration);
bool noAmPm = ((options & KLocale::TimeWithoutAmPm) == KLocale::TimeWithoutAmPm);
bool foldHours = ((options & KLocale::TimeFoldHours) == KLocale::TimeFoldHours);
bool strict = ((processing & KLocale::ProcessStrict) == KLocale::ProcessStrict);
// if seconds aren't needed, strip them from the timeFormat
if (excludeSecs) {
stripStringAndPreceedingSeparator(format, QLatin1String("%S"));
second = 0; // seconds are always 0
}
// if hours are folded, strip them from the timeFormat
if (foldHours) {
stripStringAndSucceedingSeparator(format, QLatin1String("%H"));
stripStringAndSucceedingSeparator(format, QLatin1String("%k"));
stripStringAndSucceedingSeparator(format, QLatin1String("%I"));
stripStringAndSucceedingSeparator(format, QLatin1String("%l"));
}
// if am/pm isn't needed, strip it from the timeFormat
if (noAmPm) {
stripAmPmFormat(format);
}
while (!error && (format.length() > formatpos || str.length() > strpos)) {
if (!(format.length() > formatpos && str.length() > strpos)) {
error = true;
break;
}
QChar c = format.at(formatpos++);
if (c.isSpace()) {
if (strict) { // strict processing: space is needed
if (!str.at(strpos).isSpace()) {
error = true;
break;
}
strpos++;
} else { // lax processing: space in str not needed
// 1 space maximum as str is simplified
if (str.at(strpos).isSpace()) {
strpos++;
}
}
continue;
}
if (c != QLatin1Char('%')) {
if (c != str.at(strpos++)) {
error = true;
break;
}
continue;
}
c = format.at(formatpos++);
switch (c.unicode()) {
case 'p': // Day Period, normally AM/PM
case 'P': // Lowercase Day Period, normally am/pm
{
error = true;
foreach (const KDayPeriod &testDayPeriod, dayPeriods()) {
QString dayPeriodText = testDayPeriod.periodName(KLocale::ShortName);
int len = dayPeriodText.length();
if (str.mid(strpos, len) == dayPeriodText.toLower()) {
dayPeriod = testDayPeriod;
strpos += len;
error = false;
useDayPeriod = true;
break;
}
}
break;
}
case 'k': // 24h Hours Short Number
case 'H': // 24h Hours Long Number
useDayPeriod = false;
hour = readInt(str, strpos);
break;
case 'l': // 12h Hours Short Number
case 'I': // 12h Hours Long Number
useDayPeriod = !isDuration;
hour = readInt(str, strpos);
break;
case 'M':
minute = readInt(str, strpos);
// minutes can be bigger than 59 if hours are folded
if (foldHours) {
// if hours are folded, make sure minutes doesn't get bigger than 59.
hour = minute / 60;
minute = minute % 60;
}
break;
case 'S':
second = readInt(str, strpos);
break;
}
// NOTE: if anything is performed inside this loop, be sure to
// check for error!
}
QTime returnTime;
if (!error) {
if (useDayPeriod) {
returnTime = dayPeriod.time(hour, minute, second);
} else {
returnTime = QTime(hour, minute, second);
}
}
if (ok) {
*ok = returnTime.isValid();
}
return returnTime;
}
QString KLocalePrivate::formatTime(const QTime &time, bool includeSecs, bool isDuration) const
{
KLocale::TimeFormatOptions options = KLocale::TimeDefault;
if (!includeSecs) {
options |= KLocale::TimeWithoutSeconds;
}
if (isDuration) {
options |= KLocale::TimeDuration;
}
return formatLocaleTime(time, options);
}
QString KLocalePrivate::formatLocaleTime(const QTime &time, KLocale::TimeFormatOptions options) const
{
QString rst(timeFormat());
bool excludeSecs = ((options & KLocale::TimeWithoutSeconds) == KLocale::TimeWithoutSeconds);
bool isDuration = ((options & KLocale::TimeDuration) == KLocale::TimeDuration);
bool noAmPm = ((options & KLocale::TimeWithoutAmPm) == KLocale::TimeWithoutAmPm);
bool foldHours = ((options & KLocale::TimeFoldHours) == KLocale::TimeFoldHours);
// if seconds aren't needed, strip them from the timeFormat
if (excludeSecs) {
stripStringAndPreceedingSeparator(rst, QLatin1String("%S"));
}
// if hours should be folded, strip all hour symbols from the timeFormat
if (foldHours) {
stripStringAndSucceedingSeparator(rst, QLatin1String("%H"));
stripStringAndSucceedingSeparator(rst, QLatin1String("%k"));
stripStringAndSucceedingSeparator(rst, QLatin1String("%I"));
stripStringAndSucceedingSeparator(rst, QLatin1String("%l"));
}
// if am/pm isn't needed, strip it from the timeFormat
if (noAmPm) {
stripAmPmFormat(rst);
}
// only "pm/am" and %M here can grow, the rest shrinks, but
// I'm rather safe than sorry
QChar *buffer = new QChar[rst.length() * 3 / 2 + 32];
int index = 0;
bool escape = false;
int number = 0;
for (int format_index = 0; format_index < rst.length(); format_index++) {
if (!escape) {
if (rst.at(format_index).unicode() == '%') {
escape = true;
} else {
buffer[index++] = rst.at(format_index);
}
} else {
switch (rst.at(format_index).unicode()) {
case '%':
buffer[index++] = QLatin1Char('%');
break;
case 'H':
put_it_in(buffer, index, time.hour());
break;
case 'I':
if (isDuration) {
put_it_in(buffer, index, time.hour());
} else {
put_it_in(buffer, index, dayPeriodForTime(time).hourInPeriod(time));
}
break;
case 'M':
if (foldHours) {
put_it_in(buffer, index, QString::number(time.hour() * 60 + time.minute()));
} else {
put_it_in(buffer, index, time.minute());
}
break;
case 'S':
put_it_in(buffer, index, time.second());
break;
case 'k':
case 'l':
// to share the code
if (!isDuration && rst.at(format_index).unicode() == 'l') {
number = dayPeriodForTime(time).hourInPeriod(time);
} else {
number = time.hour();
}
if (number / 10) {
buffer[index++] = number / 10 + '0';
}
buffer[index++] = number % 10 + '0';
break;
case 'p':
{
put_it_in(buffer, index, dayPeriodForTime(time).periodName(KLocale::ShortName));
break;
}
default:
buffer[index++] = rst.at(format_index);
break;
}
escape = false;
}
}
QString ret(buffer, index);
delete [] buffer;
ret = convertDigits(ret, dateTimeDigitSet());
return ret.trimmed();
}
bool KLocalePrivate::use12Clock() const
{
if ((timeFormat().contains(QString::fromLatin1("%I")) > 0) ||
(timeFormat().contains(QString::fromLatin1("%l")) > 0)) {
return true;
} else {
return false;
}
}
void KLocalePrivate::setDayPeriods(const QList<KDayPeriod> &dayPeriods)
{
if (dayPeriods.count() > 0) {
foreach (const KDayPeriod &dayPeriod, dayPeriods) {
if (!dayPeriod.isValid()) {
return;
}
}
m_dayPeriods = dayPeriods;
}
}
QList<KDayPeriod> KLocalePrivate::dayPeriods() const
{
// If no Day Periods currently loaded then it means there were no country specific ones defined
// in the country l10n file, so default to standard AM/PM translations for the users language.
// Note we couldn't do this in initDayPeriods() as i18n isn't available until we have a
// valid loacle constructed.
if (m_dayPeriods.isEmpty()) {
m_dayPeriods.append(KDayPeriod(QString::fromLatin1("am"),
i18nc( "Before Noon KLocale::LongName", "Ante Meridiem" ),
i18nc( "Before Noon KLocale::ShortName", "AM" ),
i18nc( "Before Noon KLocale::NarrowName", "A" ),
QTime( 0, 0, 0 ), QTime( 11, 59, 59, 999 ), 0, 12 ));
m_dayPeriods.append(KDayPeriod(QString::fromLatin1("pm"),
i18nc( "After Noon KLocale::LongName", "Post Meridiem" ),
i18nc( "After Noon KLocale::ShortName", "PM" ),
i18nc( "After Noon KLocale::NarrowName", "P" ),
QTime( 12, 0, 0 ), QTime( 23, 59, 59, 999 ), 0, 12 ));
}
return m_dayPeriods;
}
KDayPeriod KLocalePrivate::dayPeriodForTime(const QTime &time) const
{
if (time.isValid()) {
foreach (const KDayPeriod &dayPeriod, dayPeriods()) {
if (dayPeriod.isValid(time)) {
return dayPeriod;
}
}
}
return KDayPeriod();
}
QStringList KLocalePrivate::languageList() const
{
return m_languageList;
}
QStringList KLocalePrivate::currencyCodeList() const
{
return m_currencyCodeList;
}
QString KLocalePrivate::formatDateTime(const KLocale *locale, const QDateTime &dateTime, KLocale::DateFormat format,
bool includeSeconds, int daysTo, int secsTo)
{
// Have to do Fancy Date formatting here rather than using normal KCalendarSystem::formatDate()
// as daysTo is relative to the time spec which formatDate doesn't know about. Needs to be
// kept in sync with Fancy Date code in KCalendarSystem::formatDate(). Fix in KDE5.
// Only do Fancy if less than an hour into the future or less than a week in the past
if ((daysTo == 0 && secsTo > 3600) || daysTo < 0 || daysTo > 6) {
if (format == KLocale::FancyShortDate) {
format = KLocale::ShortDate;
} else if (format == KLocale::FancyLongDate) {
format = KLocale::LongDate;
}
}
QString dateStr;
if (format == KLocale::FancyShortDate || format == KLocale::FancyLongDate) {
switch (daysTo) {
case 0:
dateStr = i18n("Today");
break;
case 1:
dateStr = i18n("Yesterday");
break;
default:
dateStr = locale->calendar()->weekDayName(dateTime.date());
}
} else {
dateStr = locale->formatDate(dateTime.date(), format);
}
KLocale::TimeFormatOption timeFormat;
if (includeSeconds) {
timeFormat = KLocale::TimeDefault;
} else {
timeFormat = KLocale::TimeWithoutSeconds;
}
return i18nc("concatenation of dates and time", "%1 %2", dateStr,
locale->formatLocaleTime(dateTime.time(), timeFormat));
}
QString KLocalePrivate::formatDateTime(const QDateTime &dateTime, KLocale::DateFormat format, bool includeSeconds) const
{
QDateTime now = QDateTime::currentDateTime();
int daysTo = dateTime.date().daysTo(now.date());
int secsTo = now.secsTo(dateTime);
return KLocalePrivate::formatDateTime(q, dateTime, format, includeSeconds, daysTo, secsTo);
}
QString KLocalePrivate::formatDateTime(const KDateTime &dateTime, KLocale::DateFormat format,
KLocale::DateTimeFormatOptions options)
{
QString dt;
if (dateTime.isDateOnly()) {
dt = formatDate(dateTime.date(), format);
} else {
KDateTime now = KDateTime::currentDateTime(dateTime.timeSpec());
int daysTo = dateTime.date().daysTo(now.date());
int secsTo = now.secsTo(dateTime);
dt = KLocalePrivate::formatDateTime(q, dateTime.dateTime(), format, (options & KLocale::Seconds), daysTo, secsTo);
}
if (options & KLocale::TimeZone) {
QString tz;
switch (dateTime.timeType()) {
case KDateTime::OffsetFromUTC:
tz = i18n(dateTime.toString(QString::fromLatin1("%z")).toUtf8());
break;
case KDateTime::UTC:
case KDateTime::TimeZone:
tz = i18n(dateTime.toString(QString::fromLatin1((format == KLocale::ShortDate) ? "%Z" : "%:Z")).toUtf8());
break;
case KDateTime::ClockTime:
default:
break;
}
return i18nc("concatenation of date/time and time zone", "%1 %2", dt, tz);
}
return dt;
}
QString KLocalePrivate::langLookup(const QString &fname, const char *rtype)
{
QStringList search;
// assemble the local search paths
const QStringList localDoc = KGlobal::dirs()->resourceDirs(rtype);
// look up the different languages
for (int id = localDoc.count() - 1; id >= 0; --id) {
QStringList langs = KGlobal::locale()->languageList();
// FIXME: KDE 4.5, change such that English is not assumed.
langs.replaceInStrings(QLatin1String("en_US"), QLatin1String("en"));
langs.append(QLatin1String("en"));
Q_FOREACH(const QString &lang, langs)
search.append(QString::fromLatin1("%1%2/%3").arg(localDoc[id]).arg(lang).arg(fname));
}
// try to locate the file
Q_FOREACH(const QString &file, search) {
kDebug(173) << "Looking for help in: " << file;
QFileInfo info(file);
if (info.exists() && info.isFile() && info.isReadable())
return file;
}
return QString();
}
bool KLocalePrivate::useDefaultLanguage() const
{
return language() == KLocale::defaultLanguage();
}
void KLocalePrivate::initEncoding()
{
m_codecForEncoding = 0;
// This all made more sense when we still had the EncodingEnum config key.
QByteArray codeset = systemCodeset();
if (!codeset.isEmpty()) {
QTextCodec* codec = QTextCodec::codecForName(codeset);
if (codec) {
setEncoding(codec->mibEnum());
}
} else {
setEncoding(QTextCodec::codecForLocale()->mibEnum());
}
if (!m_codecForEncoding) {
kWarning() << "Cannot resolve system encoding, defaulting to ISO 8859-1.";
const int mibDefault = 4; // ISO 8859-1
setEncoding(mibDefault);
}
Q_ASSERT(m_codecForEncoding);
}
QByteArray KLocalePrivate::systemCodeset() const
{
QByteArray codeset;
#if HAVE_LANGINFO_H
// Qt since 4.2 always returns 'System' as codecForLocale and KDE (for example
// KEncodingFileDialog) expects real encoding name. So on systems that have langinfo.h use
// nl_langinfo instead, just like Qt compiled without iconv does. Windows already has its own
// workaround
codeset = nl_langinfo(CODESET);
if ((codeset == "ANSI_X3.4-1968") || (codeset == "US-ASCII")) {
// means ascii, "C"; QTextCodec doesn't know, so avoid warning
codeset = "ISO-8859-1";
}
#endif
return codeset;
}
void KLocalePrivate::initFileNameEncoding()
{
// If the following environment variable is set, assume all filenames
// are in UTF-8 regardless of the current C locale.
m_utf8FileEncoding = !qgetenv("KDE_UTF8_FILENAMES").isEmpty();
if (m_utf8FileEncoding) {
QFile::setEncodingFunction(KLocalePrivate::encodeFileNameUTF8);
QFile::setDecodingFunction(KLocalePrivate::decodeFileNameUTF8);
}
// Otherwise, stay with QFile's default filename encoding functions
// which, on Unix platforms, use the locale's codec.
}
QByteArray KLocalePrivate::encodeFileNameUTF8(const QString & fileName)
{
return fileName.toUtf8();
}
QString KLocalePrivate::decodeFileNameUTF8(const QByteArray &localFileName)
{
return QString::fromUtf8(localFileName);
}
void KLocalePrivate::setDateFormat(const QString &format)
{
m_dateFormat = format.trimmed();
}
void KLocalePrivate::setDateFormatShort(const QString &format)
{
m_dateFormatShort = format.trimmed();
}
void KLocalePrivate::setDateMonthNamePossessive(bool possessive)
{
m_dateMonthNamePossessive = possessive;
}
void KLocalePrivate::setTimeFormat(const QString &format)
{
m_timeFormat = format.trimmed();
}
void KLocalePrivate::setWeekStartDay(int day)
{
if (day >= 1 && day <= calendar()->daysInWeek(QDate())) {
m_weekStartDay = day;
}
}
void KLocalePrivate::setWorkingWeekStartDay(int day)
{
if (day >= 1 && day <= calendar()->daysInWeek(QDate())) {
m_workingWeekStartDay = day;
}
}
void KLocalePrivate::setWorkingWeekEndDay(int day)
{
if (day >= 1 && day <= calendar()->daysInWeek(QDate())) {
m_workingWeekEndDay = day;
}
}
void KLocalePrivate::setWeekDayOfPray(int day)
{
if (day >= 0 && day <= calendar()->daysInWeek(QDate())) { // 0 = None
m_weekDayOfPray = day;
}
}
QString KLocalePrivate::dateFormat() const
{
return m_dateFormat;
}
QString KLocalePrivate::dateFormatShort() const
{
return m_dateFormatShort;
}
QString KLocalePrivate::timeFormat() const
{
return m_timeFormat;
}
void KLocalePrivate::setDecimalPlaces(int digits)
{
m_decimalPlaces = digits;
}
void KLocalePrivate::setDecimalSymbol(const QString &symbol)
{
m_decimalSymbol = symbol.trimmed();
}
void KLocalePrivate::setThousandsSeparator(const QString &separator)
{
// allow spaces here
m_thousandsSeparator = separator;
}
void KLocalePrivate::setNumericDigitGrouping(QList<int> groupList)
{
m_numericDigitGrouping = groupList;
}
void KLocalePrivate::setPositiveSign(const QString &sign)
{
m_positiveSign = sign.trimmed();
}
void KLocalePrivate::setNegativeSign(const QString &sign)
{
m_negativeSign = sign.trimmed();
}
void KLocalePrivate::setPositiveMonetarySignPosition(KLocale::SignPosition signpos)
{
m_positiveMonetarySignPosition = signpos;
}
void KLocalePrivate::setNegativeMonetarySignPosition(KLocale::SignPosition signpos)
{
m_negativeMonetarySignPosition = signpos;
}
void KLocalePrivate::setPositivePrefixCurrencySymbol(bool prefix)
{
m_positivePrefixCurrencySymbol = prefix;
}
void KLocalePrivate::setNegativePrefixCurrencySymbol(bool prefix)
{
m_negativePrefixCurrencySymbol = prefix;
}
void KLocalePrivate::setMonetaryDecimalPlaces(int digits)
{
m_monetaryDecimalPlaces = digits;
}
void KLocalePrivate::setMonetaryThousandsSeparator(const QString &separator)
{
// allow spaces here
m_monetaryThousandsSeparator = separator;
}
void KLocalePrivate::setMonetaryDigitGrouping(QList<int> groupList)
{
m_monetaryDigitGrouping = groupList;
}
void KLocalePrivate::setMonetaryDecimalSymbol(const QString &symbol)
{
m_monetaryDecimalSymbol = symbol.trimmed();
}
void KLocalePrivate::setCurrencySymbol(const QString & symbol)
{
m_currencySymbol = symbol.trimmed();
}
int KLocalePrivate::pageSize() const
{
return m_pageSize;
}
void KLocalePrivate::setPageSize(int size)
{
// #### check if it's in range??
m_pageSize = size;
}
KLocale::MeasureSystem KLocalePrivate::measureSystem() const
{
return m_measureSystem;
}
void KLocalePrivate::setMeasureSystem(KLocale::MeasureSystem value)
{
m_measureSystem = value;
}
QString KLocalePrivate::defaultLanguage()
{
static const QString en_US = QString::fromLatin1("en_US");
return en_US;
}
QString KLocalePrivate::defaultCountry()
{
return QString::fromLatin1("C");
}
QString KLocalePrivate::defaultCurrencyCode()
{
return QString::fromLatin1("USD");
}
bool KLocalePrivate::useTranscript() const
{
return m_useTranscript;
}
const QByteArray KLocalePrivate::encoding()
{
return codecForEncoding()->name();
}
int KLocalePrivate::encodingMib() const
{
return codecForEncoding()->mibEnum();
}
int KLocalePrivate::fileEncodingMib() const
{
if (m_utf8FileEncoding) {
return 106;
}
return codecForEncoding()->mibEnum();
}
QTextCodec *KLocalePrivate::codecForEncoding() const
{
return m_codecForEncoding;
}
bool KLocalePrivate::setEncoding(int mibEnum)
{
QTextCodec * codec = QTextCodec::codecForMib(mibEnum);
if (codec) {
m_codecForEncoding = codec;
}
return codec != 0;
}
QStringList KLocalePrivate::allLanguagesList()
{
if (!m_languages) {
m_languages = new KConfig(QLatin1String("all_languages"), KConfig::NoGlobals, "locale");
}
return m_languages->groupList();
}
QStringList KLocalePrivate::installedLanguages()
{
QStringList languages;
QStringList paths = KGlobal::dirs()->findAllResources("locale", QLatin1String("*/entry.desktop"));
foreach (const QString &path, paths) {
QString part = path.left(path.length() - 14);
languages.append(part.mid(part.lastIndexOf(QLatin1Char('/')) + 1));
}
languages.sort();
return languages;
}
QString KLocalePrivate::languageCodeToName(const QString &language)
{
if (!m_languages) {
m_languages = new KConfig(QLatin1String("all_languages"), KConfig::NoGlobals, "locale");
}
KConfigGroup cg(m_languages, language);
return cg.readEntry("Name");
}
QStringList KLocalePrivate::allCountriesList() const
{
QStringList countries;
const QStringList paths = KGlobal::dirs()->findAllResources("locale", QLatin1String("l10n/*/entry.desktop"));
for (QStringList::ConstIterator it = paths.begin(); it != paths.end(); ++it) {
QString code = (*it).mid((*it).length() - 16, 2);
if (code != QLatin1String("/C")) {
countries.append(code);
}
}
return countries;
}
QString KLocalePrivate::countryCodeToName(const QString &country) const
{
QString countryName;
QString entryFile = KStandardDirs::locate("locale", QString::fromLatin1("l10n/") + country.toLower() + QLatin1String("/entry.desktop"));
if (!entryFile.isEmpty()) {
KConfig cfg(entryFile);
KConfigGroup cg(&cfg, "KCM Locale");
countryName = cg.readEntry("Name");
}
return countryName;
}
KLocale::CalendarSystem KLocalePrivate::calendarTypeToCalendarSystem(const QString &calendarType) const
{
if (calendarType == QLatin1String("coptic")) {
return KLocale::CopticCalendar;
} else if (calendarType == QLatin1String("ethiopian")) {
return KLocale::EthiopianCalendar;
} else if (calendarType == QLatin1String("gregorian")) {
return KLocale::QDateCalendar;
} else if (calendarType == QLatin1String("gregorian-proleptic")) {
return KLocale::GregorianCalendar;
} else if (calendarType == QLatin1String("hebrew")) {
return KLocale::HebrewCalendar;
} else if (calendarType == QLatin1String("hijri")) {
return KLocale::IslamicCivilCalendar;
} else if (calendarType == QLatin1String("indian-national")) {
return KLocale::IndianNationalCalendar;
} else if (calendarType == QLatin1String("jalali")) {
return KLocale::JalaliCalendar;
} else if (calendarType == QLatin1String("japanese")) {
return KLocale::JapaneseCalendar;
} else if (calendarType == QLatin1String("julian")) {
return KLocale::JulianCalendar;
} else if (calendarType == QLatin1String("minguo")) {
return KLocale::MinguoCalendar;
} else if (calendarType == QLatin1String("thai")) {
return KLocale::ThaiCalendar;
} else {
return KLocale::QDateCalendar;
}
}
QString KLocalePrivate::calendarSystemToCalendarType(KLocale::CalendarSystem calendarSystem) const
{
switch (calendarSystem) {
case KLocale::QDateCalendar:
return QLatin1String("gregorian");
case KLocale::CopticCalendar:
return QLatin1String("coptic");
case KLocale::EthiopianCalendar:
return QLatin1String("ethiopian");
case KLocale::GregorianCalendar:
return QLatin1String("gregorian-proleptic");
case KLocale::HebrewCalendar:
return QLatin1String("hebrew");
case KLocale::IslamicCivilCalendar:
return QLatin1String("hijri");
case KLocale::IndianNationalCalendar:
return QLatin1String("indian-national");
case KLocale::JalaliCalendar:
return QLatin1String("jalali");
case KLocale::JapaneseCalendar:
return QLatin1String("japanese");
case KLocale::JulianCalendar:
return QLatin1String("julian");
case KLocale::MinguoCalendar:
return QLatin1String("minguo");
case KLocale::ThaiCalendar:
return QLatin1String("thai");
default:
return QLatin1String("gregorian");
}
}
void KLocalePrivate::setCalendar(const QString &calendarType)
{
setCalendarSystem(calendarTypeToCalendarSystem(calendarType));
}
void KLocalePrivate::setCalendarSystem(KLocale::CalendarSystem calendarSystem)
{
m_calendarSystem = calendarSystem;
delete m_calendar;
m_calendar = 0;
}
QString KLocalePrivate::calendarType() const
{
return calendarSystemToCalendarType(m_calendarSystem);
}
KLocale::CalendarSystem KLocalePrivate::calendarSystem() const
{
return m_calendarSystem;
}
const KCalendarSystem * KLocalePrivate::calendar()
{
if (!m_calendar) {
m_calendar = KCalendarSystem::create(m_calendarSystem, m_config, q);
}
return m_calendar;
}
void KLocalePrivate::setWeekNumberSystem(KLocale::WeekNumberSystem weekNumberSystem)
{
m_weekNumberSystem = weekNumberSystem;
}
KLocale::WeekNumberSystem KLocalePrivate::weekNumberSystem()
{
return m_weekNumberSystem;
}
void KLocalePrivate::copyCatalogsTo(KLocale *locale)
{
QMutexLocker lock(kLocaleMutex());
locale->d->m_catalogNames = m_catalogNames;
locale->d->updateCatalogs();
}
QString KLocalePrivate::localizedFilePath(const QString &filePath) const
{
// Stop here if the default language is primary.
if (useDefaultLanguage()) {
return filePath;
}
// Check if l10n sudir is present, stop if not.
QFileInfo fileInfo(filePath);
QString locDirPath = fileInfo.path() + QLatin1String("/l10n");
QFileInfo locDirInfo(locDirPath);
if (!locDirInfo.isDir()) {
return filePath;
}
// Go through possible localized paths by priority of languages,
// return first that exists.
QString fileName = fileInfo.fileName();
foreach(const QString &lang, languageList()) {
// Stop when the default language is reached.
if (lang == KLocale::defaultLanguage()) {
return filePath;
}
QString locFilePath = locDirPath + QLatin1Char('/') + lang + QLatin1Char('/') + fileName;
QFileInfo locFileInfo(locFilePath);
if (locFileInfo.isFile() && locFileInfo.isReadable()) {
return locFilePath;
}
}
return filePath;
}
QString KLocalePrivate::removeAcceleratorMarker(const QString &label) const
{
return ::removeAcceleratorMarker(label);
}
void KLocalePrivate::setDigitSet(KLocale::DigitSet digitSet)
{
m_digitSet = digitSet;
}
KLocale::DigitSet KLocalePrivate::digitSet() const
{
return m_digitSet;
}
void KLocalePrivate::setMonetaryDigitSet(KLocale::DigitSet digitSet)
{
m_monetaryDigitSet = digitSet;
}
KLocale::DigitSet KLocalePrivate::monetaryDigitSet() const
{
return m_monetaryDigitSet;
}
void KLocalePrivate::setDateTimeDigitSet(KLocale::DigitSet digitSet)
{
m_dateTimeDigitSet = digitSet;
}
KLocale::DigitSet KLocalePrivate::dateTimeDigitSet() const
{
return m_dateTimeDigitSet;
}
Q_GLOBAL_STATIC_WITH_ARGS(QMutex, s_kLocaleMutex, (QMutex::Recursive))
QMutex *kLocaleMutex()
{
return s_kLocaleMutex();
}
diff --git a/kdecore/tests/klocaletest.cpp b/kdecore/tests/klocaletest.cpp
index 97a3bce9f4..f80de858c2 100644
--- a/kdecore/tests/klocaletest.cpp
+++ b/kdecore/tests/klocaletest.cpp
@@ -1,1357 +1,1381 @@
/* This file is part of the KDE libraries
Copyright (c) 2005 Thomas Braxton <brax108@cox.net>
Copyright (c) 2007 David Jarvie <software@astrojar.org.uk>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2 as published by the Free Software Foundation.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "klocaletest.h"
#include "qtest_kde.h"
#include "kdebug.h"
#include "klocale.h"
#include "klocale_p.h"
#include "kglobal.h"
#include "kconfiggroup.h"
#include "kcalendarsystem.h"
#include "kdayperiod_p.h"
#include "kdatetime.h"
#include "ksystemtimezone.h"
#include <QtCore/QString>
#include <QtCore/QDate>
#include <QtDBus/QtDBus>
#include "klocaletest.moc"
void
KLocaleTest::initTestCase()
{
KGlobal::locale()->setThousandsSeparator(QLatin1String(","));
}
void KLocaleTest::languages()
{
QVERIFY(KGlobal::locale()->installedLanguages().contains("en_US"));
}
void
KLocaleTest::formatNumbers()
{
KLocale locale(*KGlobal::locale());
KGlobal::locale()->setDecimalPlaces(2);
QCOMPARE(locale.formatNumber(70), QString("70.00"));
QCOMPARE(locale.formatNumber(70, 0), QString("70"));
QCOMPARE(locale.formatNumber(70.2), QString("70.20"));
QCOMPARE(locale.formatNumber(70.24), QString("70.24"));
QCOMPARE(locale.formatNumber(70.245), QString("70.25"));
QCOMPARE(locale.formatNumber(1234567.89123456789,8),
QString("1,234,567.89123457"));
QCOMPARE(locale.formatNumber(1234567.89123456789, 0), QString("1,234,568"));
// Test Grouping
locale.d->setNumericDigitGrouping(QList<int>());
QCOMPARE(locale.formatNumber(123456789, 0), QString("123456789"));
QCOMPARE(locale.formatNumber(123456789.01), QString("123456789.01"));
locale.d->setNumericDigitGrouping(QList<int>() << 3 << 2);
QCOMPARE(locale.formatNumber(123456789, 0), QString("12,34,56,789"));
QCOMPARE(locale.formatNumber(123456789.01), QString("12,34,56,789.01"));
locale.d->setNumericDigitGrouping(QList<int>() << 3 << -1);
QCOMPARE(locale.formatNumber(123456789, 0), QString("123456,789"));
QCOMPARE(locale.formatNumber(123456789.01), QString("123456,789.01"));
//Test it formats correctly with an empty and space separator.
locale.d->setNumericDigitGrouping(QList<int>() << 3);
QCOMPARE(locale.formatNumber(123456789, 0), QString("123,456,789"));
QCOMPARE(locale.formatNumber(123456789.01), QString("123,456,789.01"));
locale.setThousandsSeparator(QString());
QCOMPARE(locale.formatNumber(123456789, 0), QString("123456789"));
QCOMPARE(locale.formatNumber(123456789.01), QString("123456789.01"));
locale.setThousandsSeparator(" ");
QCOMPARE(locale.formatNumber(123456789, 0), QString("123 456 789"));
QCOMPARE(locale.formatNumber(123456789.01), QString("123 456 789.01"));
}
void
KLocaleTest::formatNumberStrings()
{
KLocale locale(*KGlobal::locale());
KGlobal::locale()->setDecimalPlaces(2);
QCOMPARE(locale.formatNumber("70"), QString("70.00"));
QCOMPARE(locale.formatNumber("70", true, 2), QString("70.00"));
QCOMPARE(locale.formatNumber("70", true, 0), QString("70"));
QCOMPARE(locale.formatNumber("0.2", true, 1), QString("0.2"));
QCOMPARE(locale.formatNumber("70.9123", true, 0), QString("71"));
QCOMPARE(locale.formatNumber("-70.2", true, 2), QString("-70.20"));
QCOMPARE(locale.formatNumber("+70.24", true, 2), QString("70.24"));
QCOMPARE(locale.formatNumber("70.245", true, 2), QString("70.25"));
QCOMPARE(locale.formatNumber("99.996", true, 2), QString("100.00"));
QCOMPARE(locale.formatNumber("12345678901234567.89123456789",false,0),
QString("12,345,678,901,234,567.89123456789"));
QCOMPARE(locale.formatNumber("99.9e96", true, 2), QString("99.90e96"));
QCOMPARE(locale.formatNumber("99e", true, 1), QString("99.0"));
QCOMPARE(locale.formatNumber("e2", true, 0), QString("0e2"));
QCOMPARE(locale.formatNumber("1.", true, 1), QString("1.0"));
QCOMPARE(locale.formatNumber("1.", true, 0), QString("1"));
QCOMPARE(locale.formatNumber("1.", false, 1), QString("1.")); // no rounding -> 1. unchanged
QCOMPARE(locale.formatNumber("1.", false, 0), QString("1."));
QCOMPARE(locale.formatNumber("abcd", true, 2), QString("0.00")); // invalid number
// Test Grouping
locale.d->setNumericDigitGrouping(QList<int>());
QCOMPARE(locale.formatNumber("123456789", true, 0), QString("123456789"));
QCOMPARE(locale.formatNumber("123456789.01"), QString("123456789.01"));
locale.d->setNumericDigitGrouping(QList<int>() << 3 << 2);
QCOMPARE(locale.formatNumber("123456789", true, 0), QString("12,34,56,789"));
QCOMPARE(locale.formatNumber("123456789.01"), QString("12,34,56,789.01"));
locale.d->setNumericDigitGrouping(QList<int>() << 3 << -1);
QCOMPARE(locale.formatNumber("123456789", true, 0), QString("123456,789"));
QCOMPARE(locale.formatNumber("123456789.01"), QString("123456,789.01"));
//Test it formats correctly with an empty and space separator.
locale.d->setNumericDigitGrouping(QList<int>() << 3);
QCOMPARE(locale.formatNumber("123456789", true, 0), QString("123,456,789"));
QCOMPARE(locale.formatNumber("123456789.01"), QString("123,456,789.01"));
locale.setThousandsSeparator(QString());
QCOMPARE(locale.formatNumber("123456789", true, 0), QString("123456789"));
QCOMPARE(locale.formatNumber("123456789.01"), QString("123456789.01"));
locale.setThousandsSeparator(" ");
QCOMPARE(locale.formatNumber("123456789", true, 0), QString("123 456 789"));
QCOMPARE(locale.formatNumber("123456789.01"), QString("123 456 789.01"));
}
void
KLocaleTest::readNumber()
{
KLocale locale(*KGlobal::locale());
bool ok=false;
locale.readNumber("12,1", &ok);
QVERIFY(!ok);
QCOMPARE(locale.readNumber("12,100", &ok), 12100.0);
QVERIFY(ok);
locale.readNumber("12,100000,00", &ok);
QVERIFY(!ok);
locale.readNumber("12,100000000", &ok);
QVERIFY(!ok);
locale.readNumber("12,,100,000", &ok);
QVERIFY(!ok);
locale.readNumber("12,1000,000", &ok);
QVERIFY(!ok);
locale.readNumber("12,0000000,000", &ok);
QVERIFY(!ok);
locale.readNumber("12,0000000", &ok);
QVERIFY(!ok);
QCOMPARE(locale.readNumber("12,146,131.12", &ok), 12146131.12);
QVERIFY(ok);
QCOMPARE(locale.readNumber("1.12345678912", &ok), 1.12345678912);
QVERIFY(ok);
// Test Grouping
locale.d->setNumericDigitGrouping(QList<int>());
QCOMPARE(locale.readNumber(QString("123456789"), &ok), 123456789.0);
QVERIFY(ok);
QCOMPARE(locale.readNumber(QString("123456789.01"), &ok), 123456789.01);
QVERIFY(ok);
QCOMPARE(locale.readNumber(QString("123,456,789"), &ok), 0.0);
QVERIFY(!ok);
QCOMPARE(locale.readNumber(QString("123,456,789.01"), &ok), 0.0);
QVERIFY(!ok);
locale.d->setNumericDigitGrouping(QList<int>() << 3 << 2);
QCOMPARE(locale.readNumber(QString("12,34,56,789"), &ok), 123456789.0);
QVERIFY(ok);
QCOMPARE(locale.readNumber(QString("12,34,56,789.01"), &ok), 123456789.01);
QVERIFY(ok);
QCOMPARE(locale.readNumber(QString("123,456,789"), &ok), 0.0);
QVERIFY(!ok);
QCOMPARE(locale.readNumber(QString("123,456,789.01"), &ok), 0.0);
QVERIFY(!ok);
- QCOMPARE(locale.readNumber(QString("123456789"), &ok), 0.0);
+ QCOMPARE(locale.readNumber(QString("123456789"), &ok), 123456789.0);
+ QVERIFY(ok);
+ QCOMPARE(locale.readNumber(QString("123456789.01"), &ok), 123456789.01);
+ QVERIFY(ok);
+ QCOMPARE(locale.readNumber(QString("123456,789"), &ok), 0.0);
QVERIFY(!ok);
- QCOMPARE(locale.readNumber(QString("123456789.01"), &ok), 0.0);
+ QCOMPARE(locale.readNumber(QString("123456,789.01"), &ok), 0.0);
QVERIFY(!ok);
//Test it parses correctly with an empty separator.
locale.d->setNumericDigitGrouping(QList<int>() << 3);
locale.setThousandsSeparator(QString());
QCOMPARE(locale.readNumber(QString("123456789"), &ok), 123456789.0);
QVERIFY(ok);
QCOMPARE(locale.readNumber(QString("123456789.01"), &ok), 123456789.01);
QVERIFY(ok);
QCOMPARE(locale.readNumber(QString("123,456,789"), &ok), 0.0);
QVERIFY(!ok);
QCOMPARE(locale.readNumber(QString("123,456,789.01"), &ok), 0.0);
QVERIFY(!ok);
//Test it parses correctly with an space separator.
locale.d->setNumericDigitGrouping(QList<int>() << 3);
locale.setThousandsSeparator(" ");
QCOMPARE(locale.readNumber(QString("123 456 789"), &ok), 123456789.0);
QVERIFY(ok);
QCOMPARE(locale.readNumber(QString("123 456 789.01"), &ok), 123456789.01);
QVERIFY(ok);
+ QCOMPARE(locale.readNumber(QString("123456789"), &ok), 123456789.0);
+ QVERIFY(ok);
+ QCOMPARE(locale.readNumber(QString("123456789.01"), &ok), 123456789.01);
+ QVERIFY(ok);
+ QCOMPARE(locale.readNumber(QString("123456 789"), &ok), 0.0);
+ QVERIFY(!ok);
+ QCOMPARE(locale.readNumber(QString("123456 789.01"), &ok), 0.0);
+ QVERIFY(!ok);
QCOMPARE(locale.readNumber(QString("123,456,789"), &ok), 0.0);
QVERIFY(!ok);
QCOMPARE(locale.readNumber(QString("123,456,789.01"), &ok), 0.0);
QVERIFY(!ok);
// Test signs
locale.setPositiveSign("@");
locale.setNegativeSign("&");
locale.setThousandsSeparator(",");
locale.d->setNumericDigitGrouping(QList<int>() << 3);
QCOMPARE(locale.readNumber(QString("@123,456,789.12"), &ok), 123456789.12);
QVERIFY(ok);
QCOMPARE(locale.readNumber(QString("&123,456,789.12"), &ok), -123456789.12);
QVERIFY(ok);
QCOMPARE(locale.readNumber(QString( "123,456,789.12"), &ok), 123456789.12);
QVERIFY(ok);
QCOMPARE(locale.readNumber(QString("+123,456,789.12"), &ok), 0.0);
QVERIFY(!ok);
QCOMPARE(locale.readNumber(QString("-123,456,789.12"), &ok), 0.0);
QVERIFY(!ok);
locale.setNegativeSign(QString());
QCOMPARE(locale.readNumber(QString( "123,456,789.12"), &ok), -123456789.12);
QVERIFY(ok);
QCOMPARE(locale.readNumber(QString("-123,456,789.12"), &ok), 0.0);
QVERIFY(!ok);
}
void KLocaleTest::formatMoney()
{
KLocale locale(*KGlobal::locale());
locale.setPositiveSign(QString());
locale.setNegativeSign("-");
locale.setPositivePrefixCurrencySymbol(true);
locale.setNegativePrefixCurrencySymbol(true);
locale.setMonetaryDecimalPlaces(2);
locale.setMonetaryThousandsSeparator(",");
locale.setMonetaryDecimalSymbol(".");
locale.setCurrencySymbol("$");
locale.setPositiveMonetarySignPosition(KLocale::BeforeQuantityMoney);
locale.setNegativeMonetarySignPosition(KLocale::BeforeQuantityMoney);
locale.d->setMonetaryDigitGrouping(QList<int>() << 3);
// Basic grouping, decimal place and rounding tests
QCOMPARE(locale.formatMoney( 1), QString( "$ 1.00"));
QCOMPARE(locale.formatMoney( 21), QString( "$ 21.00"));
QCOMPARE(locale.formatMoney( 321), QString( "$ 321.00"));
QCOMPARE(locale.formatMoney( 4321), QString( "$ 4,321.00"));
QCOMPARE(locale.formatMoney( 54321), QString( "$ 54,321.00"));
QCOMPARE(locale.formatMoney( 654321), QString( "$ 654,321.00"));
QCOMPARE(locale.formatMoney( 7654321), QString( "$ 7,654,321.00"));
QCOMPARE(locale.formatMoney( 87654321), QString( "$ 87,654,321.00"));
QCOMPARE(locale.formatMoney(987654321), QString("$ 987,654,321.00"));
QCOMPARE(locale.formatMoney( 1.1), QString( "$ 1.10"));
QCOMPARE(locale.formatMoney( 21.1), QString( "$ 21.10"));
QCOMPARE(locale.formatMoney( 321.1), QString( "$ 321.10"));
QCOMPARE(locale.formatMoney( 4321.1), QString( "$ 4,321.10"));
QCOMPARE(locale.formatMoney( 54321.1), QString( "$ 54,321.10"));
QCOMPARE(locale.formatMoney( 654321.1), QString( "$ 654,321.10"));
QCOMPARE(locale.formatMoney( 7654321.1), QString( "$ 7,654,321.10"));
QCOMPARE(locale.formatMoney( 87654321.1), QString( "$ 87,654,321.10"));
QCOMPARE(locale.formatMoney(987654321.1), QString("$ 987,654,321.10"));
QCOMPARE(locale.formatMoney( 1.12), QString( "$ 1.12"));
QCOMPARE(locale.formatMoney( 21.12), QString( "$ 21.12"));
QCOMPARE(locale.formatMoney( 321.12), QString( "$ 321.12"));
QCOMPARE(locale.formatMoney( 4321.12), QString( "$ 4,321.12"));
QCOMPARE(locale.formatMoney( 54321.12), QString( "$ 54,321.12"));
QCOMPARE(locale.formatMoney( 654321.12), QString( "$ 654,321.12"));
QCOMPARE(locale.formatMoney( 7654321.12), QString( "$ 7,654,321.12"));
QCOMPARE(locale.formatMoney( 87654321.12), QString( "$ 87,654,321.12"));
QCOMPARE(locale.formatMoney(987654321.12), QString("$ 987,654,321.12"));
QCOMPARE(locale.formatMoney( 1.12), QString( "$ 1.12"));
QCOMPARE(locale.formatMoney( 21.12), QString( "$ 21.12"));
QCOMPARE(locale.formatMoney( 321.12), QString( "$ 321.12"));
QCOMPARE(locale.formatMoney( 4321.12), QString( "$ 4,321.12"));
QCOMPARE(locale.formatMoney( 54321.12), QString( "$ 54,321.12"));
QCOMPARE(locale.formatMoney( 654321.12), QString( "$ 654,321.12"));
QCOMPARE(locale.formatMoney( 7654321.12), QString( "$ 7,654,321.12"));
QCOMPARE(locale.formatMoney( 87654321.12), QString( "$ 87,654,321.12"));
QCOMPARE(locale.formatMoney(987654321.12), QString("$ 987,654,321.12"));
QCOMPARE(locale.formatMoney( 1.123), QString( "$ 1.12"));
QCOMPARE(locale.formatMoney( 21.123), QString( "$ 21.12"));
QCOMPARE(locale.formatMoney( 321.123), QString( "$ 321.12"));
QCOMPARE(locale.formatMoney( 4321.123), QString( "$ 4,321.12"));
QCOMPARE(locale.formatMoney( 54321.123), QString( "$ 54,321.12"));
QCOMPARE(locale.formatMoney( 654321.123), QString( "$ 654,321.12"));
QCOMPARE(locale.formatMoney( 7654321.123), QString( "$ 7,654,321.12"));
QCOMPARE(locale.formatMoney( 87654321.123), QString( "$ 87,654,321.12"));
QCOMPARE(locale.formatMoney(987654321.123), QString("$ 987,654,321.12"));
QCOMPARE(locale.formatMoney( 1.129), QString( "$ 1.13"));
QCOMPARE(locale.formatMoney( 21.129), QString( "$ 21.13"));
QCOMPARE(locale.formatMoney( 321.129), QString( "$ 321.13"));
QCOMPARE(locale.formatMoney( 4321.129), QString( "$ 4,321.13"));
QCOMPARE(locale.formatMoney( 54321.129), QString( "$ 54,321.13"));
QCOMPARE(locale.formatMoney( 654321.129), QString( "$ 654,321.13"));
QCOMPARE(locale.formatMoney( 7654321.129), QString( "$ 7,654,321.13"));
QCOMPARE(locale.formatMoney( 87654321.129), QString( "$ 87,654,321.13"));
QCOMPARE(locale.formatMoney(987654321.129), QString("$ 987,654,321.13"));
QCOMPARE(locale.formatMoney( -1), QString( "$ -1.00"));
QCOMPARE(locale.formatMoney( -21), QString( "$ -21.00"));
QCOMPARE(locale.formatMoney( -321), QString( "$ -321.00"));
QCOMPARE(locale.formatMoney( -4321), QString( "$ -4,321.00"));
QCOMPARE(locale.formatMoney( -54321), QString( "$ -54,321.00"));
QCOMPARE(locale.formatMoney( -654321), QString( "$ -654,321.00"));
QCOMPARE(locale.formatMoney( -7654321), QString( "$ -7,654,321.00"));
QCOMPARE(locale.formatMoney( -87654321), QString( "$ -87,654,321.00"));
QCOMPARE(locale.formatMoney(-987654321), QString("$ -987,654,321.00"));
QCOMPARE(locale.formatMoney( -1.1), QString( "$ -1.10"));
QCOMPARE(locale.formatMoney( -21.1), QString( "$ -21.10"));
QCOMPARE(locale.formatMoney( -321.1), QString( "$ -321.10"));
QCOMPARE(locale.formatMoney( -4321.1), QString( "$ -4,321.10"));
QCOMPARE(locale.formatMoney( -54321.1), QString( "$ -54,321.10"));
QCOMPARE(locale.formatMoney( -654321.1), QString( "$ -654,321.10"));
QCOMPARE(locale.formatMoney( -7654321.1), QString( "$ -7,654,321.10"));
QCOMPARE(locale.formatMoney( -87654321.1), QString( "$ -87,654,321.10"));
QCOMPARE(locale.formatMoney(-987654321.1), QString("$ -987,654,321.10"));
QCOMPARE(locale.formatMoney( -1.12), QString( "$ -1.12"));
QCOMPARE(locale.formatMoney( -21.12), QString( "$ -21.12"));
QCOMPARE(locale.formatMoney( -321.12), QString( "$ -321.12"));
QCOMPARE(locale.formatMoney( -4321.12), QString( "$ -4,321.12"));
QCOMPARE(locale.formatMoney( -54321.12), QString( "$ -54,321.12"));
QCOMPARE(locale.formatMoney( -654321.12), QString( "$ -654,321.12"));
QCOMPARE(locale.formatMoney( -7654321.12), QString( "$ -7,654,321.12"));
QCOMPARE(locale.formatMoney( -87654321.12), QString( "$ -87,654,321.12"));
QCOMPARE(locale.formatMoney(-987654321.12), QString("$ -987,654,321.12"));
QCOMPARE(locale.formatMoney( -1.12), QString( "$ -1.12"));
QCOMPARE(locale.formatMoney( -21.12), QString( "$ -21.12"));
QCOMPARE(locale.formatMoney( -321.12), QString( "$ -321.12"));
QCOMPARE(locale.formatMoney( -4321.12), QString( "$ -4,321.12"));
QCOMPARE(locale.formatMoney( -54321.12), QString( "$ -54,321.12"));
QCOMPARE(locale.formatMoney( -654321.12), QString( "$ -654,321.12"));
QCOMPARE(locale.formatMoney( -7654321.12), QString( "$ -7,654,321.12"));
QCOMPARE(locale.formatMoney( -87654321.12), QString( "$ -87,654,321.12"));
QCOMPARE(locale.formatMoney(-987654321.12), QString("$ -987,654,321.12"));
QCOMPARE(locale.formatMoney( -1.123), QString( "$ -1.12"));
QCOMPARE(locale.formatMoney( -21.123), QString( "$ -21.12"));
QCOMPARE(locale.formatMoney( -321.123), QString( "$ -321.12"));
QCOMPARE(locale.formatMoney( -4321.123), QString( "$ -4,321.12"));
QCOMPARE(locale.formatMoney( -54321.123), QString( "$ -54,321.12"));
QCOMPARE(locale.formatMoney( -654321.123), QString( "$ -654,321.12"));
QCOMPARE(locale.formatMoney( -7654321.123), QString( "$ -7,654,321.12"));
QCOMPARE(locale.formatMoney( -87654321.123), QString( "$ -87,654,321.12"));
QCOMPARE(locale.formatMoney(-987654321.123), QString("$ -987,654,321.12"));
QCOMPARE(locale.formatMoney( -1.129), QString( "$ -1.13"));
QCOMPARE(locale.formatMoney( -21.129), QString( "$ -21.13"));
QCOMPARE(locale.formatMoney( -321.129), QString( "$ -321.13"));
QCOMPARE(locale.formatMoney( -4321.129), QString( "$ -4,321.13"));
QCOMPARE(locale.formatMoney( -54321.129), QString( "$ -54,321.13"));
QCOMPARE(locale.formatMoney( -654321.129), QString( "$ -654,321.13"));
QCOMPARE(locale.formatMoney( -7654321.129), QString( "$ -7,654,321.13"));
QCOMPARE(locale.formatMoney( -87654321.129), QString( "$ -87,654,321.13"));
QCOMPARE(locale.formatMoney(-987654321.129), QString("$ -987,654,321.13"));
// Test override defaults
QCOMPARE(locale.formatMoney(987654321.12, "£", 0), QString( "£ 987,654,321"));
QCOMPARE(locale.formatMoney(987654321.12, "USD", 4), QString("USD 987,654,321.1200"));
// Test Grouping
locale.d->setMonetaryDigitGrouping(QList<int>());
QCOMPARE(locale.formatMoney( 987654321.12), QString( "$ 987654321.12"));
QCOMPARE(locale.formatMoney(-987654321.12), QString("$ -987654321.12"));
locale.d->setMonetaryDigitGrouping(QList<int>() << 3 << 2);
QCOMPARE(locale.formatMoney( 987654321.12), QString( "$ 98,76,54,321.12"));
QCOMPARE(locale.formatMoney(-987654321.12), QString("$ -98,76,54,321.12"));
locale.d->setMonetaryDigitGrouping(QList<int>() << 3 << -1);
QCOMPARE(locale.formatMoney( 987654321.12), QString( "$ 987654,321.12"));
QCOMPARE(locale.formatMoney(-987654321.12), QString("$ -987654,321.12"));
// Test symbol and sign position options
locale.setPositiveSign("+");
locale.setNegativeSign("-");
locale.d->setMonetaryDigitGrouping(QList<int>() << 3);
locale.setPositiveMonetarySignPosition(KLocale::ParensAround);
locale.setNegativeMonetarySignPosition(KLocale::ParensAround);
locale.setPositivePrefixCurrencySymbol(true);
locale.setNegativePrefixCurrencySymbol(true);
QCOMPARE(locale.formatMoney( 987654321.12), QString("$ (987,654,321.12)"));
QCOMPARE(locale.formatMoney(-987654321.12), QString("$ (987,654,321.12)"));
locale.setPositivePrefixCurrencySymbol(false);
locale.setNegativePrefixCurrencySymbol(false);
QCOMPARE(locale.formatMoney( 987654321.12), QString("(987,654,321.12) $"));
QCOMPARE(locale.formatMoney(-987654321.12), QString("(987,654,321.12) $"));
locale.setPositiveMonetarySignPosition(KLocale::BeforeQuantityMoney);
locale.setNegativeMonetarySignPosition(KLocale::BeforeQuantityMoney);
locale.setPositivePrefixCurrencySymbol(true);
locale.setNegativePrefixCurrencySymbol(true);
QCOMPARE(locale.formatMoney( 987654321.12), QString("$ +987,654,321.12"));
QCOMPARE(locale.formatMoney(-987654321.12), QString("$ -987,654,321.12"));
locale.setPositivePrefixCurrencySymbol(false);
locale.setNegativePrefixCurrencySymbol(false);
QCOMPARE(locale.formatMoney( 987654321.12), QString("+987,654,321.12 $"));
QCOMPARE(locale.formatMoney(-987654321.12), QString("-987,654,321.12 $"));
locale.setPositiveMonetarySignPosition(KLocale::AfterQuantityMoney);
locale.setNegativeMonetarySignPosition(KLocale::AfterQuantityMoney);
locale.setPositivePrefixCurrencySymbol(true);
locale.setNegativePrefixCurrencySymbol(true);
QCOMPARE(locale.formatMoney( 987654321.12), QString("$ 987,654,321.12+"));
QCOMPARE(locale.formatMoney(-987654321.12), QString("$ 987,654,321.12-"));
locale.setPositivePrefixCurrencySymbol(false);
locale.setNegativePrefixCurrencySymbol(false);
QCOMPARE(locale.formatMoney( 987654321.12), QString("987,654,321.12+ $"));
QCOMPARE(locale.formatMoney(-987654321.12), QString("987,654,321.12- $"));
locale.setPositiveMonetarySignPosition(KLocale::BeforeMoney);
locale.setNegativeMonetarySignPosition(KLocale::BeforeMoney);
locale.setPositivePrefixCurrencySymbol(true);
locale.setNegativePrefixCurrencySymbol(true);
QCOMPARE(locale.formatMoney( 987654321.12), QString("+$ 987,654,321.12"));
QCOMPARE(locale.formatMoney(-987654321.12), QString("-$ 987,654,321.12"));
locale.setPositivePrefixCurrencySymbol(false);
locale.setNegativePrefixCurrencySymbol(false);
QCOMPARE(locale.formatMoney( 987654321.12), QString("987,654,321.12 +$"));
QCOMPARE(locale.formatMoney(-987654321.12), QString("987,654,321.12 -$"));
locale.setPositiveMonetarySignPosition(KLocale::AfterMoney);
locale.setNegativeMonetarySignPosition(KLocale::AfterMoney);
locale.setPositivePrefixCurrencySymbol(true);
locale.setNegativePrefixCurrencySymbol(true);
QCOMPARE(locale.formatMoney( 987654321.12), QString("$+ 987,654,321.12"));
QCOMPARE(locale.formatMoney(-987654321.12), QString("$- 987,654,321.12"));
locale.setPositivePrefixCurrencySymbol(false);
locale.setNegativePrefixCurrencySymbol(false);
QCOMPARE(locale.formatMoney( 987654321.12), QString("987,654,321.12 $+"));
QCOMPARE(locale.formatMoney(-987654321.12), QString("987,654,321.12 $-"));
}
void KLocaleTest::readMoney()
{
bool ok = false;
KLocale locale(*KGlobal::locale());
locale.setPositiveSign(QString());
locale.setNegativeSign("-");
locale.setPositivePrefixCurrencySymbol(true);
locale.setNegativePrefixCurrencySymbol(true);
locale.setMonetaryDecimalPlaces(2);
locale.setMonetaryThousandsSeparator(",");
locale.setMonetaryDecimalSymbol(".");
locale.setCurrencySymbol("$");
locale.setPositiveMonetarySignPosition(KLocale::BeforeQuantityMoney);
locale.setNegativeMonetarySignPosition(KLocale::BeforeQuantityMoney);
locale.d->setMonetaryDigitGrouping(QList<int>() << 3);
// Basic grouping, decimal place and rounding tests
QCOMPARE(locale.readMoney( "$ 1.12", &ok), 1.12);
QVERIFY(ok);
QCOMPARE(locale.readMoney( "$ 21.12", &ok), 21.12);
QVERIFY(ok);
QCOMPARE(locale.readMoney( "$ 321.12", &ok), 321.12);
QVERIFY(ok);
QCOMPARE(locale.readMoney( "$ 4,321.12", &ok), 4321.12);
QVERIFY(ok);
QCOMPARE(locale.readMoney( "$ 54,321.12", &ok), 54321.12);
QVERIFY(ok);
QCOMPARE(locale.readMoney( "$ 654,321.12", &ok), 654321.12);
QVERIFY(ok);
QCOMPARE(locale.readMoney( "$ 7,654,321.12", &ok), 7654321.12);
QVERIFY(ok);
QCOMPARE(locale.readMoney( "$ 87,654,321.12", &ok), 87654321.12);
QVERIFY(ok);
QCOMPARE(locale.readMoney("$ 987,654,321.12", &ok), 987654321.12);
QVERIFY(ok);
+ QCOMPARE(locale.readMoney("$ 987654321.12", &ok), 987654321.12);
+ QVERIFY(ok);
+ QCOMPARE(locale.readMoney("$ 987654,321.12", &ok), 0.0);
+ QVERIFY(!ok);
QCOMPARE(locale.readMoney( "$ -1.12", &ok), -1.12);
QVERIFY(ok);
QCOMPARE(locale.readMoney( "$ -21.12", &ok), -21.12);
QVERIFY(ok);
QCOMPARE(locale.readMoney( "$ -321.12", &ok), -321.12);
QVERIFY(ok);
QCOMPARE(locale.readMoney( "$ -4,321.12", &ok), -4321.12);
QVERIFY(ok);
QCOMPARE(locale.readMoney( "$ -54,321.12", &ok), -54321.12);
QVERIFY(ok);
QCOMPARE(locale.readMoney( "$ -654,321.12", &ok), -654321.12);
QVERIFY(ok);
QCOMPARE(locale.readMoney( "$ -7,654,321.12", &ok), -7654321.12);
QVERIFY(ok);
QCOMPARE(locale.readMoney( "$ -87,654,321.12", &ok), -87654321.12);
QVERIFY(ok);
QCOMPARE(locale.readMoney("$ -987,654,321.12", &ok), -987654321.12);
QVERIFY(ok);
+ QCOMPARE(locale.readMoney("$ -987654321.12", &ok), -987654321.12);
+ QVERIFY(ok);
+ QCOMPARE(locale.readMoney("$ -987654,321.12", &ok), 0.0);
+ QVERIFY(!ok);
// Test incomplete formats
QCOMPARE(locale.readMoney( "$ 1", &ok), 1.00);
QVERIFY(ok);
QCOMPARE(locale.readMoney( "$ 21", &ok), 21.00);
QVERIFY(ok);
QCOMPARE(locale.readMoney( "$ 321", &ok), 321.00);
QVERIFY(ok);
QCOMPARE(locale.readMoney( "$ 4,321", &ok), 4321.00);
QVERIFY(ok);
QCOMPARE(locale.readMoney( "$ 54,321", &ok), 54321.00);
QVERIFY(ok);
QCOMPARE(locale.readMoney( "$ 654,321", &ok), 654321.00);
QVERIFY(ok);
QCOMPARE(locale.readMoney( "$ 7,654,321", &ok), 7654321.00);
QVERIFY(ok);
QCOMPARE(locale.readMoney( "$ 87,654,321", &ok), 87654321.00);
QVERIFY(ok);
QCOMPARE(locale.readMoney("$ 987,654,321", &ok), 987654321.00);
QVERIFY(ok);
// Test Grouping
locale.d->setMonetaryDigitGrouping(QList<int>());
- QCOMPARE(locale.readMoney( "$ 987654321.12", &ok), 987654321.12);
+ QCOMPARE(locale.readMoney("$ 987654321.12", &ok), 987654321.12);
QVERIFY(ok);
QCOMPARE(locale.readMoney("$ -987654321.12", &ok), -987654321.12);
QVERIFY(ok);
locale.d->setMonetaryDigitGrouping(QList<int>() << 3 << 2);
- QCOMPARE(locale.readMoney( "$ 98,76,54,321.12", &ok), 987654321.12);
+ QCOMPARE(locale.readMoney("$ 98,76,54,321.12", &ok), 987654321.12);
QVERIFY(ok);
QCOMPARE(locale.readMoney("$ -98,76,54,321.12", &ok), -987654321.12);
QVERIFY(ok);
+ QCOMPARE(locale.readMoney("$ 987654321.12", &ok), 987654321.12);
+ QVERIFY(ok);
+ QCOMPARE(locale.readMoney("$ -987654321.12", &ok), -987654321.12);
+ QVERIFY(ok);
locale.d->setMonetaryDigitGrouping(QList<int>() << 3 << -1);
- QCOMPARE(locale.readMoney( "$ 987654,321.12", &ok), 987654321.12);
+ QCOMPARE(locale.readMoney("$ 987654,321.12", &ok), 987654321.12);
QVERIFY(ok);
QCOMPARE(locale.readMoney("$ -987654,321.12", &ok), -987654321.12);
QVERIFY(ok);
// Test signs
locale.setPositiveSign("@");
locale.setNegativeSign("&");
locale.d->setMonetaryDigitGrouping(QList<int>() << 3);
QCOMPARE(locale.readMoney(QString("$ @123,456,789.12"), &ok), 123456789.12);
QVERIFY(ok);
QCOMPARE(locale.readMoney(QString( "$ 123,456,789.12@"), &ok), 123456789.12);
QVERIFY(ok);
QCOMPARE(locale.readMoney(QString("$ &123,456,789.12"), &ok), -123456789.12);
QVERIFY(ok);
QCOMPARE(locale.readMoney(QString( "$ 123,456,789.12&"), &ok), -123456789.12);
QVERIFY(ok);
QCOMPARE(locale.readMoney(QString( "$ 123,456,789.12"), &ok), 123456789.12);
QVERIFY(ok);
QCOMPARE(locale.readMoney(QString("$ +123,456,789.12"), &ok), 0.0);
QVERIFY(!ok);
QCOMPARE(locale.readMoney(QString( "$ 123,456,789.12+"), &ok), 0.0);
QVERIFY(!ok);
QCOMPARE(locale.readMoney(QString("$ -123,456,789.12"), &ok), 0.0);
QVERIFY(!ok);
QCOMPARE(locale.readMoney(QString( "$ 123,456,789.12-"), &ok), 0.0);
QVERIFY(!ok);
locale.setNegativeSign(QString());
QCOMPARE(locale.readMoney(QString( "$ 123,456,789.12"), &ok), -123456789.12);
QVERIFY(ok);
QCOMPARE(locale.readMoney(QString("$ -123,456,789.12"), &ok), 0.0);
QVERIFY(!ok);
QCOMPARE(locale.readMoney(QString( "$ 123,456,789.12-"), &ok), 0.0);
QVERIFY(!ok);
// Test symbol and sign position options
locale.setPositiveSign("+");
locale.setNegativeSign("-");
locale.setPositiveMonetarySignPosition(KLocale::ParensAround);
locale.setNegativeMonetarySignPosition(KLocale::BeforeQuantityMoney);
locale.setPositivePrefixCurrencySymbol(true);
QCOMPARE(locale.readMoney("$ (987,654,321.12)", &ok), 987654321.12);
QVERIFY(ok);
locale.setPositivePrefixCurrencySymbol(false);
QCOMPARE(locale.readMoney("(987,654,321.12) $", &ok), 987654321.12);
QVERIFY(ok);
locale.setPositiveMonetarySignPosition(KLocale::BeforeQuantityMoney);
locale.setNegativeMonetarySignPosition(KLocale::ParensAround);
locale.setNegativePrefixCurrencySymbol(true);
QCOMPARE(locale.readMoney("$ (987,654,321.12)", &ok), -987654321.12);
QVERIFY(ok);
locale.setNegativePrefixCurrencySymbol(false);
QCOMPARE(locale.readMoney("(987,654,321.12) $", &ok), -987654321.12);
QVERIFY(ok);
locale.setPositiveMonetarySignPosition(KLocale::BeforeQuantityMoney);
locale.setNegativeMonetarySignPosition(KLocale::BeforeQuantityMoney);
locale.setPositivePrefixCurrencySymbol(true);
locale.setNegativePrefixCurrencySymbol(true);
QCOMPARE(locale.readMoney("$ +987,654,321.12", &ok), 987654321.12);
QVERIFY(ok);
QCOMPARE(locale.readMoney("$ -987,654,321.12", &ok), -987654321.12);
QVERIFY(ok);
locale.setPositivePrefixCurrencySymbol(false);
locale.setNegativePrefixCurrencySymbol(false);
QCOMPARE(locale.readMoney("+987,654,321.12 $", &ok), 987654321.12);
QVERIFY(ok);
QCOMPARE(locale.readMoney("-987,654,321.12 $", &ok), -987654321.12);
QVERIFY(ok);
locale.setPositiveMonetarySignPosition(KLocale::AfterQuantityMoney);
locale.setNegativeMonetarySignPosition(KLocale::AfterQuantityMoney);
locale.setPositivePrefixCurrencySymbol(true);
locale.setNegativePrefixCurrencySymbol(true);
QCOMPARE(locale.readMoney("$ 987,654,321.12+", &ok), 987654321.12);
QVERIFY(ok);
QCOMPARE(locale.readMoney("$ 987,654,321.12-", &ok), -987654321.12);
QVERIFY(ok);
locale.setPositivePrefixCurrencySymbol(false);
locale.setNegativePrefixCurrencySymbol(false);
QCOMPARE(locale.readMoney("987,654,321.12+ $", &ok), 987654321.12);
QVERIFY(ok);
QCOMPARE(locale.readMoney("987,654,321.12- $", &ok), -987654321.12);
QVERIFY(ok);
locale.setPositiveMonetarySignPosition(KLocale::BeforeMoney);
locale.setNegativeMonetarySignPosition(KLocale::BeforeMoney);
locale.setPositivePrefixCurrencySymbol(true);
locale.setNegativePrefixCurrencySymbol(true);
QCOMPARE(locale.readMoney("+$ 987,654,321.12", &ok), 987654321.12);
QVERIFY(ok);
QCOMPARE(locale.readMoney("-$ 987,654,321.12", &ok), -987654321.12);
QVERIFY(ok);
locale.setPositivePrefixCurrencySymbol(false);
locale.setNegativePrefixCurrencySymbol(false);
QCOMPARE(locale.readMoney("987,654,321.12 +$", &ok), 987654321.12);
QVERIFY(ok);
QCOMPARE(locale.readMoney("987,654,321.12 -$", &ok), -987654321.12);
QVERIFY(ok);
locale.setPositiveMonetarySignPosition(KLocale::AfterMoney);
locale.setNegativeMonetarySignPosition(KLocale::AfterMoney);
locale.setPositivePrefixCurrencySymbol(true);
locale.setNegativePrefixCurrencySymbol(true);
QCOMPARE(locale.readMoney("$+ 987,654,321.12", &ok), 987654321.12);
QVERIFY(ok);
QCOMPARE(locale.readMoney("$- 987,654,321.12", &ok), -987654321.12);
QVERIFY(ok);
locale.setPositivePrefixCurrencySymbol(false);
locale.setNegativePrefixCurrencySymbol(false);
QCOMPARE(locale.readMoney("987,654,321.12 $+", &ok), 987654321.12);
QVERIFY(ok);
QCOMPARE(locale.readMoney("987,654,321.12 $-", &ok), -987654321.12);
QVERIFY(ok);
}
void
KLocaleTest::formatDate()
{
KLocale locale(*KGlobal::locale());
QString small("yyyy-MM-dd");
QString full("dddd dd MMMM yyyy");
QDate date;
// Ensure that user configuration isn't messing with us;
// shouldn't happen though, since qtest_kde.h sets KDEHOME.
QCOMPARE(locale.dateFormat(), QString("%A %d %B %Y"));
date.setYMD(2002, 5, 3);
QCOMPARE(locale.formatDate(date), date.toString(full));
QCOMPARE(locale.formatDate(date, KLocale::ShortDate), date.toString(small));
date = QDate::currentDate();
QCOMPARE(locale.formatDate(date), date.toString(full));
QCOMPARE(locale.formatDate(date, KLocale::ShortDate), date.toString(small));
QCOMPARE(locale.formatDate(date, KLocale::FancyLongDate), QString("Today"));
QCOMPARE(locale.formatDate(date.addDays(-1), KLocale::FancyLongDate), QString("Yesterday"));
QDate dat = date.addDays(-2);
QCOMPARE(locale.formatDate(dat, KLocale::FancyLongDate), locale.calendar()->weekDayName(dat));
dat = date.addDays(-3);
QCOMPARE(locale.formatDate(dat, KLocale::FancyLongDate), locale.calendar()->weekDayName(dat));
dat = date.addDays(-4);
QCOMPARE(locale.formatDate(dat, KLocale::FancyLongDate), locale.calendar()->weekDayName(dat));
dat = date.addDays(-5);
QCOMPARE(locale.formatDate(dat, KLocale::FancyLongDate), locale.calendar()->weekDayName(dat));
dat = date.addDays(-6);
QCOMPARE(locale.formatDate(dat, KLocale::FancyLongDate), locale.calendar()->weekDayName(dat));
dat = date.addDays(-7);
QCOMPARE(locale.formatDate(dat, KLocale::FancyLongDate), dat.toString(full));
dat = date.addDays(1);
QCOMPARE(locale.formatDate(dat, KLocale::FancyLongDate), dat.toString(full));
}
void
KLocaleTest::readDate()
{
KLocale locale(*KGlobal::locale());
QString small("yyyy-MM-dd");
QString full("dddd dd MMMM yyyy");
bool ok=false;
QDate date;
date.setYMD( 2002, 5, 3 );
QCOMPARE(locale.readDate(date.toString(small)), date);
QCOMPARE(locale.readDate(date.toString(full)), date);
locale.readDate(date.toString(small), KLocale::NormalFormat, &ok);
QVERIFY(!ok);
locale.readDate(date.toString(full), KLocale::ShortFormat, &ok);
QVERIFY(!ok);
QString twoDigitYear("dd-MM-yy");
QCOMPARE(date.toString(twoDigitYear), QString("03-05-02"));
QCOMPARE(locale.readDate("03-05-02", "%d-%m-%y"), date);
date = QDate::currentDate();
QCOMPARE(locale.readDate(date.toString(small)), date);
QCOMPARE(locale.readDate(date.toString(full)), date);
locale.readDate(date.toString(small), KLocale::NormalFormat, &ok);
QVERIFY(!ok);
locale.readDate(date.toString(full), KLocale::ShortFormat, &ok);
QVERIFY(!ok);
locale.readDate("2005-02-31", &ok);
QVERIFY(!ok);
}
void
KLocaleTest::formatTime()
{
KLocale locale(*KGlobal::locale());
QTime time(0,22,33);
locale.setTimeFormat("%H:%M %p");
QCOMPARE(locale.formatLocaleTime(time, KLocale::TimeWithoutSeconds), QString("00:22 AM"));
QCOMPARE(locale.formatLocaleTime(time, KLocale::TimeWithoutSeconds | KLocale::TimeDuration),
QString("00:22"));
locale.setTimeFormat("%H:%M:%S %p");
QCOMPARE(locale.formatLocaleTime(time, KLocale::TimeDefault), QString("00:22:33 AM"));
QCOMPARE(locale.formatLocaleTime(time, KLocale::TimeDuration), QString("00:22:33"));
locale.setTimeFormat("%l : %M : %S %p"); // #164813
QCOMPARE(locale.formatLocaleTime(time, KLocale::TimeDefault), QString("12 : 22 : 33 AM"));
QCOMPARE(locale.formatLocaleTime(time, KLocale::TimeWithoutSeconds), QString("12 : 22 AM"));
}
void
KLocaleTest::formatDateTime()
{
KLocale locale(*KGlobal::locale());
QString small("yyyy-MM-dd hh:mm");
QString smallsecs("yyyy-MM-dd hh:mm:ss");
QString full("dddd dd MMMM yyyy hh:mm");
QString fullsecs("dddd dd MMMM yyyy hh:mm:ss");
QString tfmt(" hh:mm");
QDateTime qdt;
// Ensure that user configuration isn't messing with us;
// shouldn't happen though, since qtest_kde.h sets KDEHOME.
QCOMPARE(locale.dateFormat(), QString("%A %d %B %Y"));
qdt = QDateTime(QDate(2002, 5, 3), QTime(10, 20, 30));
QCOMPARE(locale.formatDateTime(qdt), qdt.toString(small));
QCOMPARE(locale.formatDateTime(qdt, KLocale::LongDate), qdt.toString(full));
qdt = QDateTime::currentDateTime();
QDate today = qdt.date();
QTime nowt = qdt.time();
QCOMPARE(locale.formatDateTime(qdt), qdt.toString(small));
QCOMPARE(locale.formatDateTime(qdt, KLocale::LongDate), qdt.toString(full));
QCOMPARE(locale.formatDateTime(qdt, KLocale::FancyLongDate), QString("Today" + qdt.time().toString(tfmt)));
qdt = qdt.addSecs(3605); // more than 1 hour from now
QCOMPARE(locale.formatDateTime(qdt, KLocale::FancyLongDate), qdt.toString(full));
qdt.setDate(today);
qdt.setTime(QTime(0,0,0));
QCOMPARE(locale.formatDateTime(qdt, KLocale::FancyLongDate), QString("Today" + qdt.time().toString(tfmt)));
qdt = qdt.addSecs(-1);
QCOMPARE(locale.formatDateTime(qdt, KLocale::FancyLongDate), QString("Yesterday" + qdt.time().toString(tfmt)));
qdt = qdt.addDays(2); // tomorrow
qdt.setTime(nowt);
QCOMPARE(locale.formatDateTime(qdt, KLocale::FancyLongDate), qdt.toString(full));
qdt = qdt.addDays(-2); // yesterday
QCOMPARE(locale.formatDateTime(qdt, KLocale::FancyLongDate), QString("Yesterday" + qdt.time().toString(tfmt)));
qdt = qdt.addDays(-1);
QCOMPARE(locale.formatDateTime(qdt, KLocale::FancyLongDate), QString(locale.calendar()->weekDayName(qdt.date()) + qdt.time().toString(tfmt)));
qdt = qdt.addDays(-1);
QCOMPARE(locale.formatDateTime(qdt, KLocale::FancyLongDate), QString(locale.calendar()->weekDayName(qdt.date()) + qdt.time().toString(tfmt)));
qdt = qdt.addDays(-1);
QCOMPARE(locale.formatDateTime(qdt, KLocale::FancyLongDate), QString(locale.calendar()->weekDayName(qdt.date()) + qdt.time().toString(tfmt)));
qdt = qdt.addDays(-1);
QCOMPARE(locale.formatDateTime(qdt, KLocale::FancyLongDate), QString(locale.calendar()->weekDayName(qdt.date()) + qdt.time().toString(tfmt)));
qdt = qdt.addDays(-1);
QCOMPARE(locale.formatDateTime(qdt, KLocale::FancyLongDate), QString(locale.calendar()->weekDayName(qdt.date()) + qdt.time().toString(tfmt)));
qdt = qdt.addDays(-1);
QCOMPARE(locale.formatDateTime(qdt, KLocale::FancyLongDate), qdt.toString(full));
// The use of KSystemTimeZones requires kded to be running
if (!QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.kded")) {
QSKIP( "kded not running", SkipAll );
}
small = "%Y-%m-%d %H:%M";
smallsecs = "%Y-%m-%d %H:%M:%S";
full = "%A %d %B %Y %H:%M";
fullsecs = "%A %d %B %Y %H:%M:%S";
KDateTime kdt;
const KTimeZone tz = KSystemTimeZones::zone("Pacific/Fiji");
if (!tz.isValid())
QSKIP( "Pacific/Fiji timezone not available", SkipAll );
kdt = KDateTime::currentDateTime(tz);
today = kdt.date();
nowt = kdt.time();
QCOMPARE(locale.formatDateTime(kdt), kdt.toString(small));
// QCOMPARE(locale.formatDateTime(kdt, KLocale::ShortDate, KLocale::Seconds), kdt.toString(smallsecs));
QCOMPARE(locale.formatDateTime(kdt, KLocale::LongDate), kdt.toString(full));
// QCOMPARE(locale.formatDateTime(kdt, KLocale::LongDate, KLocale::Seconds), kdt.toString(fullsecs));
// QCOMPARE(locale.formatDateTime(kdt, KLocale::FancyLongDate), QString("Today") + kdt.time().toString(tfmt));
kdt = kdt.addSecs(3605); // more than 1 hour from now
QCOMPARE(locale.formatDateTime(kdt, KLocale::FancyLongDate), kdt.toString(full));
kdt.setDate(today);
kdt.setTime(QTime(0,0,0));
QCOMPARE(locale.formatDateTime(kdt, KLocale::FancyLongDate), QString("Today" + kdt.time().toString(tfmt)));
kdt = kdt.addSecs(-1);
QCOMPARE(locale.formatDateTime(kdt, KLocale::FancyLongDate), QString("Yesterday" + kdt.time().toString(tfmt)));
kdt = kdt.addDays(2); // tomorrow
kdt.setTime(nowt);
QCOMPARE(locale.formatDateTime(kdt, KLocale::FancyLongDate), kdt.toString(full));
kdt = kdt.addDays(-2); // yesterday
QCOMPARE(locale.formatDateTime(kdt, KLocale::FancyLongDate), QString("Yesterday" + kdt.time().toString(tfmt)));
kdt = kdt.addDays(-1);
QCOMPARE(locale.formatDateTime(kdt, KLocale::FancyLongDate), QString(locale.calendar()->weekDayName(kdt.date()) + kdt.time().toString(tfmt)));
kdt = kdt.addDays(-1);
QCOMPARE(locale.formatDateTime(kdt, KLocale::FancyLongDate), QString(locale.calendar()->weekDayName(kdt.date()) + kdt.time().toString(tfmt)));
kdt = kdt.addDays(-1);
QCOMPARE(locale.formatDateTime(kdt, KLocale::FancyLongDate), QString(locale.calendar()->weekDayName(kdt.date()) + kdt.time().toString(tfmt)));
kdt = kdt.addDays(-1);
QCOMPARE(locale.formatDateTime(kdt, KLocale::FancyLongDate), QString(locale.calendar()->weekDayName(kdt.date()) + kdt.time().toString(tfmt)));
kdt = kdt.addDays(-1);
QCOMPARE(locale.formatDateTime(kdt, KLocale::FancyLongDate), QString(locale.calendar()->weekDayName(kdt.date()) + kdt.time().toString(tfmt)));
kdt = kdt.addDays(-1);
QCOMPARE(locale.formatDateTime(kdt, KLocale::FancyLongDate), kdt.toString(full));
}
void
KLocaleTest::readTime()
{
KLocale locale(*KGlobal::locale());
bool ok = false;
QCOMPARE(locale.readTime("11:22:33", &ok), QTime(11,22,33));
QVERIFY(ok);
QCOMPARE(locale.readTime("11:22", &ok), QTime(11,22,0));
QVERIFY(ok);
locale.readLocaleTime("11:22:33", &ok, KLocale::TimeWithoutSeconds);
QVERIFY(!ok);
QCOMPARE(locale.readLocaleTime("11:22", &ok, KLocale::TimeWithoutSeconds), QTime(11, 22, 0));
QVERIFY(ok);
// strict processing of a time string with a missing space
locale.setTimeFormat("%I:%M:%S %p");
QString timeString = QString("11:13:55%1").arg(locale.d->dayPeriodForTime(QTime(11,13,55)).periodName());
locale.readLocaleTime(timeString, &ok, KLocale::TimeDefault, KLocale::ProcessStrict);
QVERIFY(!ok);
// lax processing of the same time
QCOMPARE(locale.readLocaleTime(timeString, &ok, KLocale::TimeDefault), QTime(11, 13, 55));
QVERIFY(ok);
}
void KLocaleTest::testDayPeriods()
{
KLocale locale(*KGlobal::locale());
locale.setTimeFormat("%I:%M:%S %p");
//Test default standard AM/PM Day Periods
KDayPeriod testPeriod;
QCOMPARE( testPeriod.isValid(), false );
testPeriod = locale.d->dayPeriodForTime( QTime( 03, 00, 00 ) );
QCOMPARE( testPeriod.isValid(), true );
QCOMPARE( testPeriod.periodName(KLocale::LongName), QString( "Ante Meridiem" ) );
QCOMPARE( testPeriod.periodName(KLocale::ShortName), QString( "AM" ) );
QCOMPARE( testPeriod.periodName(KLocale::NarrowName), QString( "A" ) );
QCOMPARE( testPeriod.periodStart(), QTime( 0, 0, 0 ) );
QCOMPARE( testPeriod.periodEnd(), QTime( 11, 59, 59, 999 ) );
QCOMPARE( testPeriod.hourInPeriod( QTime( 0, 0, 0 ) ), 12 );
QCOMPARE( testPeriod.hourInPeriod( QTime( 1, 0, 0 ) ), 1 );
QCOMPARE( testPeriod.hourInPeriod( QTime( 6, 0, 0 ) ), 6 );
QCOMPARE( testPeriod.hourInPeriod( QTime( 11, 59, 59, 999) ), 11 );
QCOMPARE( testPeriod.hourInPeriod( QTime( 12, 0, 0 ) ), -1 );
QCOMPARE( testPeriod.time( 12, 0, 0 ), QTime( 0, 0, 0 ) );
QCOMPARE( testPeriod.time( 1, 0, 0 ), QTime( 1, 0, 0 ) );
QCOMPARE( testPeriod.time( 6, 0, 0 ), QTime( 6, 0, 0 ) );
QCOMPARE( testPeriod.time( 11, 59, 59, 999 ), QTime( 11, 59, 59, 999 ) );
QCOMPARE( testPeriod.time( 13, 0, 0 ), QTime() );
testPeriod = locale.d->dayPeriodForTime( QTime( 13, 00, 00 ) );
QCOMPARE( testPeriod.isValid(), true );
QCOMPARE( testPeriod.periodName(KLocale::LongName), QString( "Post Meridiem" ) );
QCOMPARE( testPeriod.periodName(KLocale::ShortName), QString( "PM" ) );
QCOMPARE( testPeriod.periodName(KLocale::NarrowName), QString( "P" ) );
QCOMPARE( testPeriod.periodStart(), QTime( 12, 0, 0 ) );
QCOMPARE( testPeriod.periodEnd(), QTime( 23, 59, 59, 999 ) );
QCOMPARE( testPeriod.hourInPeriod( QTime( 11, 59, 59, 999) ), -1 );
QCOMPARE( testPeriod.hourInPeriod( QTime( 12, 0, 0 ) ), 12 );
QCOMPARE( testPeriod.hourInPeriod( QTime( 13, 0, 0 ) ), 1 );
QCOMPARE( testPeriod.hourInPeriod( QTime( 18, 0, 0 ) ), 6 );
QCOMPARE( testPeriod.hourInPeriod( QTime( 23, 59, 59, 999) ), 11 );
QCOMPARE( testPeriod.hourInPeriod( QTime( 24, 0, 0 ) ), -1 );
QCOMPARE( testPeriod.time( 12, 0, 0 ), QTime( 12, 0, 0 ) );
QCOMPARE( testPeriod.time( 1, 0, 0 ), QTime( 13, 0, 0 ) );
QCOMPARE( testPeriod.time( 6, 0, 0 ), QTime( 18, 0, 0 ) );
QCOMPARE( testPeriod.time( 11, 59, 59, 999 ), QTime( 23, 59, 59, 999 ) );
QCOMPARE( testPeriod.time( 13, 0, 0 ), QTime() );
QCOMPARE( locale.dayPeriodText( QTime( 11, 12, 13 ) ), QString( "AM" ) );
QCOMPARE( locale.dayPeriodText( QTime( 23, 12, 13 ) ), QString( "PM" ) );
QCOMPARE( locale.formatLocaleTime( QTime( 11, 12, 13 ) ), QString( "11:12:13 AM" ) );
QCOMPARE( locale.formatLocaleTime( QTime( 23, 12, 13 ) ), QString( "11:12:13 PM" ) );
QCOMPARE( locale.readLocaleTime( QString( "11:12:13 AM" ) ), QTime( 11, 12, 13 ) );
QCOMPARE( locale.readLocaleTime( QString( "11:12:13 PM" ) ), QTime( 23, 12, 13 ) );
QCOMPARE( locale.readLocaleTime( QString( "11:12:13 am" ) ), QTime( 11, 12, 13 ) );
QCOMPARE( locale.readLocaleTime( QString( "11:12:13 pm" ) ), QTime( 23, 12, 13 ) );
// Test setting own periods
// Test alternative periods, e.g. thirds of day with absolute hours in each period numbered 1..8
QList<KDayPeriod> dayPeriods;
dayPeriods.append( KDayPeriod( "p1", "Early Day", "Early", "E", QTime( 0, 0, 0 ), QTime( 7, 59, 59, 999 ), 1, 0 ) );
dayPeriods.append( KDayPeriod( "p2", "Middle Day", "Middle", "M", QTime( 8, 0, 0 ), QTime( 15, 59, 59, 999 ), 1, 0 ) );
dayPeriods.append( KDayPeriod( "p3", "Late Day", "Late", "L", QTime( 16, 0, 0 ), QTime( 23, 59, 59, 999 ), 1, 0 ) );
locale.d->setDayPeriods( dayPeriods );
testPeriod = locale.d->dayPeriodForTime( QTime( 0, 0, 0 ) );
QCOMPARE( testPeriod.periodName(KLocale::ShortName), QString( "Early" ) );
QCOMPARE( testPeriod.hourInPeriod( QTime( 0, 0, 0 ) ), 1 );
QCOMPARE( testPeriod.hourInPeriod( QTime( 4, 0, 0 ) ), 5 );
QCOMPARE( testPeriod.hourInPeriod( QTime( 7, 0, 0 ) ), 8 );
QCOMPARE( testPeriod.time( 0, 0, 0 ), QTime() );
QCOMPARE( testPeriod.time( 1, 0, 0 ), QTime( 0, 0, 0 ) );
QCOMPARE( testPeriod.time( 5, 0, 0 ), QTime( 4, 0, 0 ) );
QCOMPARE( testPeriod.time( 8, 0, 0 ), QTime( 7, 0, 0 ) );
QCOMPARE( testPeriod.time( 9, 0, 0 ), QTime() );
testPeriod = locale.d->dayPeriodForTime( QTime( 8, 0, 0 ) );
QCOMPARE( testPeriod.periodName(KLocale::ShortName), QString( "Middle" ) );
QCOMPARE( testPeriod.hourInPeriod( QTime( 8, 0, 0 ) ), 1 );
QCOMPARE( testPeriod.hourInPeriod( QTime( 12, 0, 0 ) ), 5 );
QCOMPARE( testPeriod.hourInPeriod( QTime( 15, 0, 0 ) ), 8 );
QCOMPARE( testPeriod.time( 0, 0, 0 ), QTime() );
QCOMPARE( testPeriod.time( 1, 0, 0 ), QTime( 8, 0, 0 ) );
QCOMPARE( testPeriod.time( 5, 0, 0 ), QTime( 12, 0, 0 ) );
QCOMPARE( testPeriod.time( 8, 0, 0 ), QTime( 15, 0, 0 ) );
QCOMPARE( testPeriod.time( 9, 0, 0 ), QTime() );
testPeriod = locale.d->dayPeriodForTime( QTime( 16, 0, 0 ) );
QCOMPARE( testPeriod.periodName(KLocale::ShortName), QString( "Late" ) );
QCOMPARE( testPeriod.hourInPeriod( QTime( 16, 0, 0 ) ), 1 );
QCOMPARE( testPeriod.hourInPeriod( QTime( 20, 0, 0 ) ), 5 );
QCOMPARE( testPeriod.hourInPeriod( QTime( 23, 0, 0 ) ), 8 );
QCOMPARE( testPeriod.time( 0, 0, 0 ), QTime() );
QCOMPARE( testPeriod.time( 1, 0, 0 ), QTime( 16, 0, 0 ) );
QCOMPARE( testPeriod.time( 5, 0, 0 ), QTime( 20, 0, 0 ) );
QCOMPARE( testPeriod.time( 8, 0, 0 ), QTime( 23, 0, 0 ) );
QCOMPARE( testPeriod.time( 9, 0, 0 ), QTime() );
QCOMPARE( locale.formatLocaleTime( QTime( 4, 0, 0 ) ), QString( "05:00:00 Early" ) );
QCOMPARE( locale.formatLocaleTime( QTime( 12, 0, 0 ) ), QString( "05:00:00 Middle" ) );
QCOMPARE( locale.formatLocaleTime( QTime( 20, 0, 0 ) ), QString( "05:00:00 Late" ) );
QCOMPARE( locale.readLocaleTime( QString( "05:00:00 Early" ) ), QTime( 4, 0, 0 ) );
QCOMPARE( locale.readLocaleTime( QString( "05:00:00 Middle" ) ), QTime( 12, 0, 0 ) );
QCOMPARE( locale.readLocaleTime( QString( "05:00:00 Late" ) ), QTime( 20, 0, 0 ) );
// Test more conventional alternative periods, e.g. informal periods of day with 12 hour clock
dayPeriods.clear();
dayPeriods.append( KDayPeriod( "morning", "Morning", "in the morning", "M", QTime( 6, 0, 0 ), QTime( 11, 59, 59, 999 ), 6, 12 ) );
dayPeriods.append( KDayPeriod( "noon", "Noon", "noon", "O", QTime( 12, 0, 0 ), QTime( 12, 0, 59, 999 ), 12, 0 ) );
dayPeriods.append( KDayPeriod( "afternoon", "Afternoon", "in the afternoon", "A", QTime( 12, 1, 0 ), QTime( 17, 59, 59, 999 ), 0, 12 ) );
dayPeriods.append( KDayPeriod( "evening", "Evening", "in the evening", "E", QTime( 18, 0, 0 ), QTime( 21, 59, 59, 999 ), 6, 12 ) );
dayPeriods.append( KDayPeriod( "night", "Night", "at night", "N", QTime( 22, 0, 0 ), QTime( 5, 59, 59, 999 ), 10, 12 ) );
locale.d->setDayPeriods( dayPeriods );
testPeriod = locale.d->dayPeriodForTime( QTime( 8, 0, 0 ) );
QCOMPARE( testPeriod.periodName( KLocale::ShortName ), QString( "in the morning" ) );
QCOMPARE( testPeriod.hourInPeriod( QTime( 8, 0, 0 ) ), 8 );
QCOMPARE( testPeriod.time( 8, 0, 0 ), QTime( 8, 0, 0 ) );
testPeriod = locale.d->dayPeriodForTime( QTime( 12, 0, 0 ) );
QCOMPARE( testPeriod.periodName( KLocale::ShortName ), QString( "noon" ) );
QCOMPARE( testPeriod.hourInPeriod( QTime( 12, 0, 0 ) ), 12 );
QCOMPARE( testPeriod.time( 12, 0, 0 ), QTime( 12, 0, 0 ) );
testPeriod = locale.d->dayPeriodForTime( QTime( 12, 1, 0 ) );
QCOMPARE( testPeriod.periodName( KLocale::ShortName ), QString( "in the afternoon" ) );
QCOMPARE( testPeriod.hourInPeriod( QTime( 12, 1, 0 ) ), 12 );
QCOMPARE( testPeriod.time( 12, 1, 0 ), QTime( 12, 1, 0 ) );
testPeriod = locale.d->dayPeriodForTime( QTime( 23, 0, 0 ) );
QCOMPARE( testPeriod.periodName( KLocale::ShortName ), QString( "at night" ) );
QCOMPARE( testPeriod.hourInPeriod( QTime( 23, 0, 0 ) ), 11 );
QCOMPARE( testPeriod.hourInPeriod( QTime( 0, 0, 0 ) ), 12 );
QCOMPARE( testPeriod.hourInPeriod( QTime( 1, 0, 0 ) ), 1 );
QCOMPARE( testPeriod.time( 11, 0, 0 ), QTime( 23, 0, 0 ) );
QCOMPARE( testPeriod.time( 12, 0, 0 ), QTime( 0, 0, 0 ) );
QCOMPARE( testPeriod.time( 1, 0, 0 ), QTime( 1, 0, 0 ) );
testPeriod = locale.d->dayPeriodForTime( QTime( 0, 0, 0 ) );
QCOMPARE( testPeriod.periodName( KLocale::ShortName ), QString( "at night" ) );
QCOMPARE( locale.readLocaleTime( QString( "8:00:00 in the morning" ) ), QTime( 8, 0, 0 ) );
QCOMPARE( locale.readLocaleTime( QString( "12:00:00 noon" ) ), QTime( 12, 0, 0 ) );
QCOMPARE( locale.readLocaleTime( QString( "5:00:00 in the afternoon" ) ), QTime( 17, 0, 0 ) );
QCOMPARE( locale.readLocaleTime( QString( "11:00:00 at night" ) ), QTime( 23, 0, 0 ) );
QCOMPARE( locale.readLocaleTime( QString( "1:00:00 at night" ) ), QTime( 1, 0, 0 ) );
locale.setTimeFormat("%l %p");
QCOMPARE( locale.formatLocaleTime( QTime( 8, 0, 0 ) ), QString( "8 in the morning" ) );
QCOMPARE( locale.formatLocaleTime( QTime( 12, 0, 0 ) ), QString( "12 noon" ) );
QCOMPARE( locale.formatLocaleTime( QTime( 17, 0, 0 ) ), QString( "5 in the afternoon" ) );
QCOMPARE( locale.formatLocaleTime( QTime( 23, 0, 0 ) ), QString( "11 at night" ) );
QCOMPARE( locale.formatLocaleTime( QTime( 1, 0, 0 ) ), QString( "1 at night" ) );
// Test load config
KConfig *testConfig = new KConfig( QString(), KConfig::SimpleConfig );
KConfigGroup testGroup( testConfig, "Locale" );
testGroup.writeEntry( "DayPeriod1",
QStringList() << "third1" << "First Third" << "T1" << "T" <<
QTime( 0, 0, 0 ).toString("HH:mm:ss.zzz") << QTime( 7, 59, 59, 999 ).toString("HH:mm:ss.zzz") <<
QString::number(0) << QString::number(12) );
testGroup.writeEntry( "DayPeriod2",
QStringList() << "third2" << "Second Third" << "T2" << "S" <<
QTime( 8, 0, 0 ).toString("HH:mm:ss.zzz") << QTime( 15, 59, 59, 999 ).toString("HH:mm:ss.zzz") <<
QString::number(8) << QString::number(12) );
testGroup.writeEntry( "DayPeriod3",
QStringList() << "third3" << "First Third" << "T3" << "R" <<
QTime( 16, 0, 0 ).toString("HH:mm:ss.zzz") << QTime( 23, 59, 59, 999 ).toString("HH:mm:ss.zzz") <<
QString::number(4) << QString::number(12) );
locale = KLocale("klocaletest", "en_us", "us", testConfig);
QCOMPARE( locale.d->dayPeriodForTime( QTime( 1, 0, 0 ) ).periodName( KLocale::ShortName ), QString( "T1" ) );
QCOMPARE( locale.d->dayPeriodForTime( QTime( 11, 0, 0 ) ).periodName( KLocale::ShortName ), QString( "T2" ) );
QCOMPARE( locale.d->dayPeriodForTime( QTime( 21, 0, 0 ) ).periodName( KLocale::ShortName ), QString( "T3" ) );
}
void KLocaleTest::testCalendarSystemType()
{
KLocale locale(*KGlobal::locale());
locale.setCalendar("coptic");
QCOMPARE( locale.calendarSystem(), KLocale::CopticCalendar);
QCOMPARE( locale.calendarType(), QString("coptic") );
locale.setCalendar("ethiopian");
QCOMPARE( locale.calendarSystem(), KLocale::EthiopianCalendar);
QCOMPARE( locale.calendarType(), QString("ethiopian") );
locale.setCalendar("gregorian-proleptic");
QCOMPARE( locale.calendarSystem(), KLocale::GregorianCalendar);
QCOMPARE( locale.calendarType(), QString("gregorian-proleptic") );
locale.setCalendar("hebrew");
QCOMPARE( locale.calendarSystem(), KLocale::HebrewCalendar);
QCOMPARE( locale.calendarType(), QString("hebrew") );
locale.setCalendar("hijri");
QCOMPARE( locale.calendarSystem(), KLocale::IslamicCivilCalendar);
QCOMPARE( locale.calendarType(), QString("hijri") );
locale.setCalendar("indian-national");
QCOMPARE( locale.calendarSystem(), KLocale::IndianNationalCalendar);
QCOMPARE( locale.calendarType(), QString("indian-national") );
locale.setCalendar("jalali");
QCOMPARE( locale.calendarSystem(), KLocale::JalaliCalendar);
QCOMPARE( locale.calendarType(), QString("jalali") );
locale.setCalendar("japanese");
QCOMPARE( locale.calendarSystem(), KLocale::JapaneseCalendar);
QCOMPARE( locale.calendarType(), QString("japanese") );
locale.setCalendar("julian");
QCOMPARE( locale.calendarSystem(), KLocale::JulianCalendar);
QCOMPARE( locale.calendarType(), QString("julian") );
locale.setCalendar("minguo");
QCOMPARE( locale.calendarSystem(), KLocale::MinguoCalendar);
QCOMPARE( locale.calendarType(), QString("minguo") );
locale.setCalendar("thai");
QCOMPARE( locale.calendarSystem(), KLocale::ThaiCalendar);
QCOMPARE( locale.calendarType(), QString("thai") );
locale.setCalendar("gregorian");
QCOMPARE( locale.calendarSystem(), KLocale::QDateCalendar);
QCOMPARE( locale.calendarType(), QString("gregorian") );
locale.setCalendarSystem(KLocale::CopticCalendar);
QCOMPARE( locale.calendarSystem(), KLocale::CopticCalendar);
QCOMPARE( locale.calendarType(), QString("coptic") );
locale.setCalendarSystem(KLocale::EthiopianCalendar);
QCOMPARE( locale.calendarSystem(), KLocale::EthiopianCalendar);
QCOMPARE( locale.calendarType(), QString("ethiopian") );
locale.setCalendarSystem(KLocale::GregorianCalendar);
QCOMPARE( locale.calendarSystem(), KLocale::GregorianCalendar);
QCOMPARE( locale.calendarType(), QString("gregorian-proleptic") );
locale.setCalendarSystem(KLocale::HebrewCalendar);
QCOMPARE( locale.calendarSystem(), KLocale::HebrewCalendar);
QCOMPARE( locale.calendarType(), QString("hebrew") );
locale.setCalendarSystem(KLocale::IslamicCivilCalendar);
QCOMPARE( locale.calendarSystem(), KLocale::IslamicCivilCalendar);
QCOMPARE( locale.calendarType(), QString("hijri") );
locale.setCalendarSystem(KLocale::IndianNationalCalendar);
QCOMPARE( locale.calendarSystem(), KLocale::IndianNationalCalendar);
QCOMPARE( locale.calendarType(), QString("indian-national") );
locale.setCalendarSystem(KLocale::JalaliCalendar);
QCOMPARE( locale.calendarSystem(), KLocale::JalaliCalendar);
QCOMPARE( locale.calendarType(), QString("jalali") );
locale.setCalendarSystem(KLocale::JapaneseCalendar);
QCOMPARE( locale.calendarSystem(), KLocale::JapaneseCalendar);
QCOMPARE( locale.calendarType(), QString("japanese") );
locale.setCalendarSystem(KLocale::JulianCalendar);
QCOMPARE( locale.calendarSystem(), KLocale::JulianCalendar);
QCOMPARE( locale.calendarType(), QString("julian") );
locale.setCalendarSystem(KLocale::MinguoCalendar);
QCOMPARE( locale.calendarSystem(), KLocale::MinguoCalendar);
QCOMPARE( locale.calendarType(), QString("minguo") );
locale.setCalendarSystem(KLocale::ThaiCalendar);
QCOMPARE( locale.calendarSystem(), KLocale::ThaiCalendar);
QCOMPARE( locale.calendarType(), QString("thai") );
locale.setCalendarSystem(KLocale::QDateCalendar);
QCOMPARE( locale.calendarSystem(), KLocale::QDateCalendar);
QCOMPARE( locale.calendarType(), QString("gregorian") );
}
void KLocaleTest::testCountryDivision()
{
KLocale locale(*KGlobal::locale());
QCOMPARE( locale.countryDivisionCode(), locale.country().toUpper() );
QVERIFY( locale.setCountryDivisionCode( "US-NY" ) );
QCOMPARE( locale.countryDivisionCode(), QString( "US-NY" ) );
}
void
KLocaleTest::prettyFormatDuration()
{
KLocale locale(*KGlobal::locale());
QCOMPARE(locale.prettyFormatDuration(1000), QString("1 second"));
QCOMPARE(locale.prettyFormatDuration(5000), QString("5 seconds"));
QCOMPARE(locale.prettyFormatDuration(60000), QString("1 minute"));
QCOMPARE(locale.prettyFormatDuration(300000), QString("5 minutes"));
QCOMPARE(locale.prettyFormatDuration(3600000), QString("1 hour"));
QCOMPARE(locale.prettyFormatDuration(18000000), QString("5 hours"));
QCOMPARE(locale.prettyFormatDuration(75000), QString("1 minute and 15 seconds"));
// Problematic case #1 (there is a reference to this case on klocale.cpp)
QCOMPARE(locale.prettyFormatDuration(119999), QString("2 minutes"));
// This case is strictly 2 hours, 15 minutes and 59 seconds. However, since the range is
// pretty high between hours and seconds, prettyFormatDuration always omits seconds when there
// are hours in scene.
QCOMPARE(locale.prettyFormatDuration(8159000), QString("2 hours and 15 minutes"));
// This case is strictly 1 hour and 10 seconds. For the same reason, prettyFormatDuration
// detects that 10 seconds is just garbage compared to 1 hour, and omits it on the result.
QCOMPARE(locale.prettyFormatDuration(3610000), QString("1 hour"));
}
void
KLocaleTest::formatByteSize()
{
KLocale locale(*KGlobal::locale());
QCOMPARE(locale.formatByteSize(0), QString("0 B"));
QCOMPARE(locale.formatByteSize(50), QString("50 B"));
QCOMPARE(locale.formatByteSize(500), QString("500 B"));
QCOMPARE(locale.formatByteSize(5000), QString("4.9 KiB"));
QCOMPARE(locale.formatByteSize(50000), QString("48.8 KiB"));
QCOMPARE(locale.formatByteSize(500000), QString("488.3 KiB"));
QCOMPARE(locale.formatByteSize(5000000), QString("4.8 MiB"));
QCOMPARE(locale.formatByteSize(50000000), QString("47.7 MiB"));
QCOMPARE(locale.formatByteSize(500000000), QString("476.8 MiB"));
#if (__WORDSIZE == 64) || defined (_LP64) || defined(__LP64__) || defined(__ILP64__)
QCOMPARE(locale.formatByteSize(5000000000), QString("4.7 GiB"));
QCOMPARE(locale.formatByteSize(50000000000), QString("46.6 GiB"));
QCOMPARE(locale.formatByteSize(500000000000), QString("465.7 GiB"));
QCOMPARE(locale.formatByteSize(5000000000000), QString("4.5 TiB"));
QCOMPARE(locale.formatByteSize(50000000000000), QString("45.5 TiB"));
QCOMPARE(locale.formatByteSize(500000000000000), QString("454.7 TiB"));
#endif
}
void
KLocaleTest::bug95511()
{
KLocale locale(*KGlobal::locale());
bool ok=false;
locale.setCurrencySymbol("$$");
QCOMPARE(locale.readMoney("1,234,567,890.12$$", &ok), 1234567890.12);
QVERIFY(ok);
QCOMPARE(locale.readMoney("-1,234,567,890.12$$", &ok), -1234567890.12);
QVERIFY(ok);
locale.setCurrencySymbol("dollars");
QCOMPARE(locale.readMoney("12,345,678,901,234,567 dollars", &ok),
12345678901234567.00);
QVERIFY(ok);
QCOMPARE(locale.readMoney("-12,345,678,901.00 dollars", &ok),
-12345678901.00);
QVERIFY(ok);
}
void KLocaleTest::weekDays()
{
KLocale locale(*KGlobal::locale());
//Test setting of weekStartDay
locale.setWeekStartDay(3);
QCOMPARE(locale.weekStartDay(), 3);
locale.setWeekStartDay(0);
QCOMPARE(locale.weekStartDay(), 3);
locale.setWeekStartDay(8);
QCOMPARE(locale.weekStartDay(), 3);
//Test setting of workingWeekStartDay
locale.setWorkingWeekStartDay(3);
locale.setWorkingWeekEndDay(6);
QCOMPARE(locale.workingWeekStartDay(), 3);
locale.setWorkingWeekStartDay(0);
QCOMPARE(locale.workingWeekStartDay(), 3);
locale.setWorkingWeekStartDay(8);
QCOMPARE(locale.workingWeekStartDay(), 3);
//Test setting of workingWeekEndDay
locale.setWorkingWeekStartDay(3);
locale.setWorkingWeekEndDay(6);
QCOMPARE(locale.workingWeekEndDay(), 6);
locale.setWorkingWeekEndDay(0);
QCOMPARE(locale.workingWeekEndDay(), 6);
locale.setWorkingWeekEndDay(8);
QCOMPARE(locale.workingWeekEndDay(), 6);
//Test setting of weekStartDay
locale.setWeekDayOfPray(3);
QCOMPARE(locale.weekDayOfPray(), 3);
locale.setWeekDayOfPray(-1);
QCOMPARE(locale.weekDayOfPray(), 3);
locale.setWeekDayOfPray(8);
QCOMPARE(locale.weekDayOfPray(), 3);
locale.setWeekDayOfPray(0);
QCOMPARE(locale.weekDayOfPray(), 0);
}
void
KLocaleTest::removeAcceleratorMarker()
{
KLocale locale(*KGlobal::locale());
// No accelerator marker.
QCOMPARE(locale.removeAcceleratorMarker(QString()),
QString());
QCOMPARE(locale.removeAcceleratorMarker("Foo bar"),
QString("Foo bar"));
// Run of the mill.
QCOMPARE(locale.removeAcceleratorMarker("&Foo bar"),
QString("Foo bar"));
QCOMPARE(locale.removeAcceleratorMarker("Foo &bar"),
QString("Foo bar"));
QCOMPARE(locale.removeAcceleratorMarker("Foo b&ar"),
QString("Foo bar"));
// - presence of escaped ampersands
QCOMPARE(locale.removeAcceleratorMarker("Foo && Bar"),
QString("Foo & Bar"));
QCOMPARE(locale.removeAcceleratorMarker("Foo && &Bar"),
QString("Foo & Bar"));
QCOMPARE(locale.removeAcceleratorMarker("&Foo && Bar"),
QString("Foo & Bar"));
// CJK-style markers.
QCOMPARE(locale.removeAcceleratorMarker("Foo bar (&F)"),
QString("Foo bar"));
QCOMPARE(locale.removeAcceleratorMarker("(&F) Foo bar"),
QString("Foo bar"));
// - interpunction after/before parenthesis still qualifies CJK marker
QCOMPARE(locale.removeAcceleratorMarker("Foo bar (&F):"),
QString("Foo bar:"));
QCOMPARE(locale.removeAcceleratorMarker("Foo bar (&F)..."),
QString("Foo bar..."));
QCOMPARE(locale.removeAcceleratorMarker("...(&F) foo bar"),
QString("...foo bar"));
// - alphanumerics around parenthesis disqualify CJK marker
QCOMPARE(locale.removeAcceleratorMarker("Foo (&F) bar"),
QString("Foo (F) bar"));
// - something removed raw ampersands, leaving dangling reduced CJK markers.
// Remove reduced markers only if CJK characters are found in the string.
QCOMPARE(locale.removeAcceleratorMarker(QString::fromUtf8("Foo bar (F)")),
QString::fromUtf8("Foo bar (F)"));
QCOMPARE(locale.removeAcceleratorMarker(QString::fromUtf8("印刷(P)...")),
QString::fromUtf8("印刷..."));
// Shady cases, where ampersand is obviously not a marker
// and should have been escaped, but it was not.
QCOMPARE(locale.removeAcceleratorMarker("&"),
QString("&"));
QCOMPARE(locale.removeAcceleratorMarker("Foo bar &"),
QString("Foo bar &"));
QCOMPARE(locale.removeAcceleratorMarker("Foo & Bar"),
QString("Foo & Bar"));
}
void
KLocaleTest::formatByteSize2()
{
KLocale locale(*KGlobal::locale());
// IEC is also default
locale.setBinaryUnitDialect(KLocale::IECBinaryDialect);
QCOMPARE(locale.binaryUnitDialect(), KLocale::IECBinaryDialect);
QCOMPARE(locale.formatByteSize(1024.0), QString("1.0 KiB"));
QCOMPARE(locale.formatByteSize(1023.0), QString("1,023 B"));
QCOMPARE(locale.formatByteSize(1163000.0), QString("1.1 MiB")); // 1.2 metric
locale.setBinaryUnitDialect(KLocale::JEDECBinaryDialect);
QCOMPARE(locale.binaryUnitDialect(), KLocale::JEDECBinaryDialect);
QCOMPARE(locale.formatByteSize(1024.0), QString("1.0 KB"));
QCOMPARE(locale.formatByteSize(1023.0), QString("1,023 B"));
QCOMPARE(locale.formatByteSize(1163000.0), QString("1.1 MB"));
locale.setBinaryUnitDialect(KLocale::MetricBinaryDialect);
QCOMPARE(locale.binaryUnitDialect(), KLocale::MetricBinaryDialect);
QCOMPARE(locale.formatByteSize(1024.0), QString("1.0 kB"));
QCOMPARE(locale.formatByteSize(1023.0), QString("1.0 kB"));
QCOMPARE(locale.formatByteSize(1163000.0), QString("1.2 MB"));
// Ensure specific dialects work, still on metric by default
QCOMPARE(locale.formatByteSize(1024.0, 1, KLocale::JEDECBinaryDialect), QString("1.0 KB"));
QCOMPARE(locale.formatByteSize(2097152.0, 1, KLocale::IECBinaryDialect), QString("2.0 MiB"));
locale.setBinaryUnitDialect(KLocale::JEDECBinaryDialect);
QCOMPARE(locale.binaryUnitDialect(), KLocale::JEDECBinaryDialect);
QCOMPARE(locale.formatByteSize(2097152.0, 1, KLocale::MetricBinaryDialect), QString("2.1 MB"));
// Ensure all units are represented (still in JEDEC mode)
QCOMPARE(locale.formatByteSize(2.0e9, 1, KLocale::MetricBinaryDialect), QString("2.0 GB"));
QCOMPARE(locale.formatByteSize(3.2e12, 1, KLocale::MetricBinaryDialect), QString("3.2 TB"));
QCOMPARE(locale.formatByteSize(4.1e15, 1, KLocale::MetricBinaryDialect), QString("4.1 PB"));
QCOMPARE(locale.formatByteSize(6.7e18, 2, KLocale::MetricBinaryDialect), QString("6.70 EB"));
QCOMPARE(locale.formatByteSize(5.6e20, 2, KLocale::MetricBinaryDialect), QString("560.00 EB"));
QCOMPARE(locale.formatByteSize(2.3e22, 2, KLocale::MetricBinaryDialect), QString("23.00 ZB"));
QCOMPARE(locale.formatByteSize(1.0e27, 1, KLocale::MetricBinaryDialect), QString("1,000.0 YB"));
// Spattering of specific units
QCOMPARE(locale.formatByteSize(823000, 3, KLocale::IECBinaryDialect, KLocale::UnitMegaByte), QString("0.785 MiB"));
QCOMPARE(locale.formatByteSize(1234034.0, 4, KLocale::JEDECBinaryDialect, KLocale::UnitByte), QString("1,234,034 B"));
}
QTEST_KDEMAIN_CORE(KLocaleTest)

File Metadata

Mime Type
text/x-diff
Expires
Fri, Nov 1, 8:03 AM (1 d, 3 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
10074696
Default Alt Text
(173 KB)

Event Timeline