00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "klocale.h"
00026
00027 #include <config.h>
00028
00029 #ifdef HAVE_SYS_TIME_H
00030 #include <sys/time.h>
00031 #endif
00032 #ifdef HAVE_TIME_H
00033 #include <time.h>
00034 #endif
00035 #ifdef HAVE_LANGINFO_H
00036 #include <langinfo.h>
00037 #endif
00038
00039 #include <QtCore/QTextCodec>
00040 #include <QtCore/QFile>
00041 #include <QtGui/QPrinter>
00042 #include <QtCore/QFileInfo>
00043 #include <QtCore/QRegExp>
00044 #include <QtCore/QLocale>
00045
00046 #include "kcatalog_p.h"
00047 #include "kglobal.h"
00048 #include "kstandarddirs.h"
00049 #include "kconfig.h"
00050 #include "kcomponentdata.h"
00051 #include "kdebug.h"
00052 #include "kdatetime.h"
00053 #include "kcalendarsystem.h"
00054 #include "klocalizedstring.h"
00055 #include "ktranslit_p.h"
00056 #include "kconfiggroup.h"
00057 #include "kcatalogname_p.h"
00058 #include "common_helpers_p.h"
00059
00060 #ifdef Q_WS_WIN
00061 #include <windows.h>
00062 #endif
00063
00064 static const char *maincatalog = 0;
00065
00066 QDebug operator<<(QDebug debug, const KCatalogName &cn)
00067 {
00068 return debug << cn.name << cn.loadCount;
00069 }
00070
00071 class KLocalePrivate
00072 {
00073 public:
00074 KLocalePrivate(const QString& catalog, KConfig *config, const QString &language_ = QString(), const QString &country_ = QString());
00081 void initMainCatalogs(const QString & catalog);
00082
00091 void initLanguageList(KConfig *config, bool useEnv);
00092
00096 void initEncoding();
00097
00102 void initFileNameEncoding();
00103
00107 static QByteArray encodeFileNameUTF8( const QString & fileName );
00108
00112 static QString decodeFileNameUTF8( const QByteArray & localFileName );
00113
00117 void initFormat(KConfig *config);
00118
00122 bool setLanguage(const QString & _language, KConfig *config);
00123
00127 bool setLanguage(const QStringList & languages);
00128
00132 bool setEncoding(int mibEnum);
00133
00137 void translate_priv(const char *msgctxt,
00138 const char *msgid,
00139 const char *msgid_plural = 0,
00140 unsigned long n = 0,
00141 QString *language = 0,
00142 QString *translation = 0) const;
00143
00147 bool useDefaultLanguage() const;
00148
00153 void updateCatalogs( );
00154
00160 bool isApplicationTranslatedInto( const QString & language);
00161
00165 static QString formatDateTime(const KLocale *locale, const QDateTime &dateTime,
00166 KLocale::DateFormat, bool includeSeconds, int daysToNow);
00170 static QString fancyDate(const KLocale *locale, const QDate &date, int daysToNow);
00171
00172 enum DurationType {
00173 DaysDurationType = 0,
00174 HoursDurationType,
00175 MinutesDurationType,
00176 SecondsDurationType
00177 };
00181 static QString formatSingleDuration( DurationType durationType, int n );
00182
00183
00184 QString decimalSymbol;
00185 QString thousandsSeparator;
00186 QString currencySymbol;
00187 QString monetaryDecimalSymbol;
00188 QString monetaryThousandsSeparator;
00189 QString positiveSign;
00190 QString negativeSign;
00191 int fracDigits;
00192 KLocale::SignPosition positiveMonetarySignPosition;
00193 KLocale::SignPosition negativeMonetarySignPosition;
00194 bool positivePrefixCurrencySymbol : 1;
00195 bool negativePrefixCurrencySymbol : 1;
00196
00197
00198 QString timeFormat;
00199 QString dateFormat;
00200 QString dateFormatShort;
00201 int weekStartDay;
00202 int workingWeekStartDay;
00203 int workingWeekEndDay;
00204 int weekDayOfPray;
00205
00206
00207 QString language;
00208 QString country;
00209
00210
00211 QStringList languageList;
00212
00213 QList<KCatalogName> catalogNames;
00214 QList<KCatalog> catalogs;
00215 int numberOfSysCatalogs;
00216 bool useTranscript;
00217
00218
00219 QString encoding;
00220 QTextCodec * codecForEncoding;
00221
00222 int pageSize;
00223 KLocale::MeasureSystem measureSystem;
00224 KConfig * languages;
00225
00226 QString calendarType;
00227 KCalendarSystem * calendar;
00228 QString appName;
00229 bool nounDeclension:1;
00230 bool dateMonthNamePossessive:1;
00231 bool utf8FileEncoding:1;
00232 #ifdef Q_WS_WIN
00233 char win32SystemEncoding[3+7];
00234 #endif
00235 };
00236
00237 KLocalePrivate::KLocalePrivate(const QString& catalog, KConfig *config, const QString &language_, const QString &country_)
00238 : language(language_),
00239 country(country_),
00240 useTranscript(false), codecForEncoding(0),
00241 languages(0), calendar(0), appName(catalog)
00242 {
00243 initEncoding();
00244 initFileNameEncoding();
00245
00246 if (config) {
00247 initLanguageList(config, false);
00248 }
00249 else {
00250 config = KGlobal::config().data();
00251 initLanguageList(config, true);
00252 }
00253
00254 initMainCatalogs(catalog);
00255
00256 initFormat(config);
00257 }
00258
00259 KLocale::KLocale( const QString & catalog, KSharedConfig::Ptr config )
00260 : d(new KLocalePrivate(catalog, config.data()))
00261 {
00262 }
00263
00264 KLocale::KLocale(const QString& catalog, const QString &language, const QString &country, KConfig *config)
00265 : d(new KLocalePrivate(catalog, config, language, country))
00266 {
00267 }
00268
00269 void KLocalePrivate::initMainCatalogs(const QString & catalog)
00270 {
00271
00272 QString mainCatalog = catalog;
00273 if (maincatalog)
00274 mainCatalog = QString::fromLatin1(maincatalog);
00275
00276 if (mainCatalog.isEmpty()) {
00277 kDebug(173) << "KLocale instance created called without valid "
00278 << "catalog! Give an argument or call setMainCatalog "
00279 << "before init" << endl;
00280 }
00281 else {
00282
00283 catalogNames.append(KCatalogName(mainCatalog));
00284
00285
00286 numberOfSysCatalogs = 4;
00287 catalogNames.append(KCatalogName("libphonon"));
00288 catalogNames.append(KCatalogName("kio4"));
00289 catalogNames.append(KCatalogName("kdelibs4"));
00290 catalogNames.append(KCatalogName("kdeqt"));
00291
00292 updateCatalogs();
00293 }
00294 }
00295
00296 static inline void getLanguagesFromVariable(QStringList& list, const char* variable)
00297 {
00298 QByteArray var( qgetenv(variable) );
00299 if (!var.isEmpty())
00300 list += QFile::decodeName(var).split(':');
00301 }
00302
00303 void KLocalePrivate::initLanguageList(KConfig *config, bool useEnv)
00304 {
00305 KConfigGroup cg(config, "Locale");
00306
00307
00308
00309 if (country.isEmpty())
00310 country = cg.readEntry("Country");
00311 if (country.isEmpty())
00312 country = KLocale::defaultCountry();
00313
00314
00315
00316
00317
00318
00319
00320 QStringList list;
00321
00322 if (!language.isEmpty())
00323 list.append(language);
00324
00325
00326 if (useEnv)
00327 getLanguagesFromVariable(list, "KDE_LANG");
00328
00329
00330 QString languages(cg.readEntry("Language", QString()));
00331 if (!languages.isEmpty())
00332 list += languages.split(':');
00333
00334
00335 QStringList rawList;
00336 if (useEnv) {
00337
00338
00339
00340
00341 getLanguagesFromVariable(list, "LANGUAGE");
00342
00343
00344
00345 getLanguagesFromVariable(rawList, "LC_ALL");
00346 getLanguagesFromVariable(rawList, "LC_MESSAGES");
00347 getLanguagesFromVariable(rawList, "LANG");
00348 }
00349 #ifdef Q_WS_WIN // how about Mac?
00350 rawList += QLocale::system().name();
00351 #endif
00352
00353 #ifndef Q_WS_WIN
00354 if (useEnv)
00355 #endif
00356 {
00357
00358 foreach (const QString &ln, rawList) {
00359 QString lang, ctry, modf, cset;
00360 KLocale::splitLocale(ln, lang, ctry, modf, cset);
00361
00362 if (!ctry.isEmpty() && !modf.isEmpty()) {
00363 list += lang + '_' + ctry + '@' + modf;
00364 }
00365
00366
00367
00368 if (!modf.isEmpty()) {
00369 list += lang + '@' + modf;
00370 }
00371 if (!ctry.isEmpty()) {
00372 list += lang + '_' + ctry;
00373 }
00374 list += lang;
00375 }
00376 }
00377
00378
00379 setLanguage(list);
00380 }
00381
00382 void KLocalePrivate::initFormat(KConfig *config)
00383 {
00384 Q_ASSERT(config);
00385
00386
00387
00388 config->setLocale(language);
00389
00390 KConfigGroup cg(config, "Locale");
00391
00392 KConfig entryFile(KStandardDirs::locate("locale",
00393 QString::fromLatin1("l10n/%1/entry.desktop")
00394 .arg(country)));
00395 entryFile.setLocale(language);
00396 KConfigGroup entry(&entryFile, "KCM Locale");
00397
00398
00399 #define readConfigEntry(key, default, save) \
00400 save = entry.readEntry(key, default); \
00401 save = cg.readEntry(key, save);
00402
00403 #define readConfigNumEntry(key, default, save, type) \
00404 save = (type)entry.readEntry(key, int(default)); \
00405 save = (type)cg.readEntry(key, int(save));
00406
00407 readConfigEntry("DecimalSymbol", ".", decimalSymbol);
00408 readConfigEntry("ThousandsSeparator", ",", thousandsSeparator);
00409 thousandsSeparator.remove( QString::fromLatin1("$0") );
00410
00411
00412 readConfigEntry("PositiveSign", "", positiveSign);
00413 readConfigEntry("NegativeSign", "-", negativeSign);
00414
00415
00416 readConfigEntry("CurrencySymbol", "$", currencySymbol);
00417 readConfigEntry("MonetaryDecimalSymbol", ".", monetaryDecimalSymbol);
00418 readConfigEntry("MonetaryThousandsSeparator", ",",
00419 monetaryThousandsSeparator);
00420 monetaryThousandsSeparator.remove(QString::fromLatin1("$0"));
00421
00422 readConfigNumEntry("FracDigits", 2, fracDigits, int);
00423 readConfigEntry("PositivePrefixCurrencySymbol", true,
00424 positivePrefixCurrencySymbol);
00425 readConfigEntry("NegativePrefixCurrencySymbol", true,
00426 negativePrefixCurrencySymbol);
00427 readConfigNumEntry("PositiveMonetarySignPosition", KLocale::BeforeQuantityMoney,
00428 positiveMonetarySignPosition, KLocale::SignPosition);
00429 readConfigNumEntry("NegativeMonetarySignPosition", KLocale::ParensAround,
00430 negativeMonetarySignPosition, KLocale::SignPosition);
00431
00432
00433 readConfigEntry("TimeFormat", "%H:%M:%S", timeFormat);
00434 readConfigEntry("DateFormat", "%A %d %B %Y", dateFormat);
00435 readConfigEntry("DateFormatShort", "%Y-%m-%d", dateFormatShort);
00436 readConfigNumEntry("WeekStartDay", 1, weekStartDay, int);
00437 readConfigNumEntry("WorkingWeekStartDay", 1, workingWeekStartDay, int);
00438 readConfigNumEntry("WorkingWeekEndDay", 5, workingWeekEndDay, int);
00439 readConfigNumEntry("WeekDayOfPray", 7, weekDayOfPray, int);
00440
00441
00442 readConfigNumEntry("PageSize", QPrinter::A4, pageSize,
00443 QPrinter::PageSize);
00444 readConfigNumEntry("MeasureSystem", KLocale::Metric,
00445 measureSystem, KLocale::MeasureSystem);
00446 readConfigEntry("CalendarSystem", "gregorian", calendarType);
00447 delete calendar;
00448 calendar = 0;
00449
00450 readConfigEntry("Transcript", true, useTranscript);
00451
00452
00453
00454 KConfig langCfg(KStandardDirs::locate("locale",
00455 QString::fromLatin1("%1/entry.desktop")
00456 .arg(language)));
00457 KConfigGroup lang(&langCfg,"KCM Locale");
00458 #define read3ConfigBoolEntry(key, default, save) \
00459 save = entry.readEntry(key, default); \
00460 save = lang.readEntry(key, save); \
00461 save = cg.readEntry(key, save);
00462
00463 read3ConfigBoolEntry("NounDeclension", false, nounDeclension);
00464 read3ConfigBoolEntry("DateMonthNamePossessive", false,
00465 dateMonthNamePossessive);
00466 }
00467
00468 bool KLocale::setCountry(const QString & aCountry, KConfig *config)
00469 {
00470
00471 if ( aCountry.isEmpty() )
00472 return false;
00473
00474 d->country = aCountry;
00475
00476 d->initFormat(config);
00477
00478 return true;
00479 }
00480
00481 bool KLocale::setLanguage(const QString & language, KConfig *config)
00482 {
00483 return d->setLanguage(language, config);
00484 }
00485
00486 bool KLocalePrivate::setLanguage(const QString & _language, KConfig *config)
00487 {
00488 if ( languageList.contains( _language ) ) {
00489 languageList.removeAll( _language );
00490 }
00491 languageList.prepend( _language );
00492
00493 language = _language;
00494
00495
00496
00497 updateCatalogs();
00498
00499 initFormat(config);
00500
00501 return true;
00502 }
00503
00504 bool KLocale::setLanguage(const QStringList & languages)
00505 {
00506 return d->setLanguage(languages);
00507 }
00508
00509 bool KLocalePrivate::setLanguage(const QStringList & languages)
00510 {
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521 QStringList list;
00522 foreach (const QString &language, languages) {
00523 if (!language.isEmpty() && !list.contains(language) && isApplicationTranslatedInto(language)) {
00524 list.append(language);
00525 }
00526 }
00527
00528 if ( !list.contains( KLocale::defaultLanguage() ) ) {
00529
00530
00531
00532 list.append( KLocale::defaultLanguage() );
00533 }
00534
00535 language = list.first();
00536
00537 languageList = list;
00538
00539
00540
00541 updateCatalogs();
00542
00543 return true;
00544 }
00545
00546 bool KLocale::isApplicationTranslatedInto( const QString & lang)
00547 {
00548 return d->isApplicationTranslatedInto( lang );
00549 }
00550
00551 bool KLocalePrivate::isApplicationTranslatedInto( const QString & lang)
00552 {
00553 if ( lang.isEmpty() ) {
00554 return false;
00555 }
00556
00557 if ( lang == KLocale::defaultLanguage() ) {
00558
00559 return true;
00560 }
00561
00562 if (maincatalog) {
00563 appName = QString::fromLatin1(maincatalog);
00564 }
00565
00566
00567 QStringList possibles;
00568 possibles += lang;
00569 possibles += KTranslit::fallbackList(lang);
00570 foreach (const QString &lang, possibles) {
00571 if ( ! KCatalog::catalogLocaleDir( appName, lang ).isEmpty() ) {
00572 return true;
00573 }
00574 }
00575 return false;
00576 }
00577
00578 void KLocale::splitLocale(const QString &aLocale,
00579 QString &language,
00580 QString &country,
00581 QString &modifier,
00582 QString &charset)
00583 {
00584 QString locale = aLocale;
00585
00586 language.clear();
00587 country.clear();
00588 modifier.clear();
00589 charset.clear();
00590
00591
00592
00593 int f = locale.indexOf(':');
00594 if (f >= 0) {
00595 locale.truncate(f);
00596 }
00597
00598 f = locale.indexOf('.');
00599 if (f >= 0) {
00600 charset = locale.mid(f + 1);
00601 locale.truncate(f);
00602 }
00603
00604 f = locale.indexOf('@');
00605 if (f >= 0) {
00606 modifier = locale.mid(f + 1);
00607 locale.truncate(f);
00608 }
00609
00610 f = locale.indexOf('_');
00611 if (f >= 0) {
00612 country = locale.mid(f + 1);
00613 locale.truncate(f);
00614 }
00615
00616 language = locale;
00617 }
00618
00619 QString KLocale::language() const
00620 {
00621 return d->language;
00622 }
00623
00624 QString KLocale::country() const
00625 {
00626 return d->country;
00627 }
00628
00629 void KLocale::insertCatalog( const QString & catalog )
00630 {
00631 int pos = d->catalogNames.indexOf(KCatalogName(catalog));
00632 if (pos != -1) {
00633 ++d->catalogNames[pos].loadCount;
00634 return;
00635 }
00636
00637
00638
00639 d->catalogNames.insert(d->catalogNames.size() - d->numberOfSysCatalogs,
00640 KCatalogName(catalog));
00641 d->updateCatalogs();
00642 }
00643
00644 void KLocalePrivate::updateCatalogs( )
00645 {
00646
00647
00648
00649
00650 catalogs.clear();
00651
00652
00653 QStringList languageListFB;
00654 foreach (const QString &lang, languageList) {
00655 languageListFB += lang;
00656 languageListFB += KTranslit::fallbackList(lang);
00657 }
00658
00659
00660
00661
00662
00663 foreach ( const QString &lang, languageListFB )
00664 foreach ( const KCatalogName &name, catalogNames )
00665
00666 if ( ! KCatalog::catalogLocaleDir( name.name, lang ).isEmpty() )
00667 {
00668 catalogs.append( KCatalog( name.name, lang ) );
00669
00670 }
00671
00672
00673 KLocalizedString::notifyCatalogsUpdated(languageListFB, catalogNames);
00674 }
00675
00676 void KLocale::removeCatalog(const QString &catalog)
00677 {
00678 int pos = d->catalogNames.indexOf(KCatalogName(catalog));
00679 if (pos == -1)
00680 return;
00681 if (--d->catalogNames[pos].loadCount > 0)
00682 return;
00683 d->catalogNames.removeAt(pos);
00684 if (KGlobal::hasMainComponent())
00685 d->updateCatalogs();
00686 }
00687
00688 void KLocale::setActiveCatalog(const QString &catalog)
00689 {
00690 int pos = d->catalogNames.indexOf(KCatalogName(catalog));
00691 if (pos == -1)
00692 return;
00693 d->catalogNames.move(pos, 0);
00694 d->updateCatalogs();
00695 }
00696
00697 KLocale::~KLocale()
00698 {
00699 delete d->calendar;
00700 delete d->languages;
00701 delete d;
00702 }
00703
00704 void KLocalePrivate::translate_priv(const char *msgctxt,
00705 const char *msgid,
00706 const char *msgid_plural,
00707 unsigned long n,
00708 QString *language,
00709 QString *translation) const
00710 {
00711 if ( !msgid || !msgid[0] ) {
00712 kDebug(173) << "KLocale: trying to look up \"\" in catalog. "
00713 << "Fix the program" << endl;
00714 language->clear();
00715 translation->clear();
00716 return;
00717 }
00718 if ( msgctxt && !msgctxt[0] ) {
00719 kDebug(173) << "KLocale: trying to use \"\" as context to message. "
00720 << "Fix the program" << endl;
00721 }
00722 if ( msgid_plural && !msgid_plural[0] ) {
00723 kDebug(173) << "KLocale: trying to use \"\" as plural message. "
00724 << "Fix the program" << endl;
00725 }
00726
00727
00728 QString fallback;
00729 if ( msgid_plural == NULL )
00730 fallback = QString::fromUtf8( msgid );
00731 else {
00732 if ( n == 1 )
00733 fallback = QString::fromUtf8( msgid );
00734 else
00735 fallback = QString::fromUtf8( msgid_plural );
00736 }
00737 if ( language )
00738 *language = KLocale::defaultLanguage();
00739 if ( translation )
00740 *translation = fallback;
00741
00742
00743 if ( useDefaultLanguage() )
00744 return;
00745
00746 for ( QList<KCatalog>::ConstIterator it = catalogs.begin();
00747 it != catalogs.end();
00748 ++it )
00749 {
00750
00751
00752
00753 if ( (*it).language() == KLocale::defaultLanguage() )
00754 return;
00755
00756 QString text;
00757 if ( msgctxt != NULL && msgid_plural != NULL )
00758 text = (*it).translateStrict( msgctxt, msgid, msgid_plural, n );
00759 else if ( msgid_plural != NULL )
00760 text = (*it).translateStrict( msgid, msgid_plural, n );
00761 else if ( msgctxt != NULL )
00762 text = (*it).translateStrict( msgctxt, msgid );
00763 else
00764 text = (*it).translateStrict( msgid );
00765
00766 if ( !text.isEmpty() ) {
00767
00768 if ( language )
00769 *language = (*it).language();
00770 if ( translation )
00771 *translation = text;
00772 return;
00773 }
00774 }
00775 }
00776
00777 void KLocale::translateRaw(const char* msg,
00778 QString *lang, QString *trans) const
00779 {
00780 d->translate_priv(0, msg, 0, 0, lang, trans);
00781 }
00782
00783 void KLocale::translateRaw(const char *ctxt, const char *msg,
00784 QString *lang, QString *trans) const
00785 {
00786 d->translate_priv(ctxt, msg, 0, 0, lang, trans);
00787 }
00788
00789 void KLocale::translateRaw(const char *singular, const char *plural, unsigned long n,
00790 QString *lang, QString *trans) const
00791 {
00792 d->translate_priv(0, singular, plural, n, lang, trans);
00793 }
00794
00795 void KLocale::translateRaw(const char *ctxt, const char *singular, const char *plural,
00796 unsigned long n,
00797 QString *lang, QString *trans) const
00798 {
00799 d->translate_priv(ctxt, singular, plural, n, lang, trans);
00800 }
00801
00802 QString KLocale::translateQt(const char *context, const char *sourceText,
00803 const char *comment) const
00804 {
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827 if (!sourceText || !sourceText[0]) {
00828 kDebug(173) << "KLocale: trying to look up \"\" in catalog. "
00829 << "Fix the program" << endl;
00830 return QString();
00831 }
00832
00833 if (d->useDefaultLanguage()) {
00834 return QString();
00835 }
00836
00837 QString translation;
00838 QString language;
00839
00840
00841
00842
00843 if (comment && comment[0]) {
00844
00845 d->translate_priv(comment, sourceText, 0, 0, &language, &translation);
00846 }
00847 else {
00848
00849 if (context && context[0]) {
00850 d->translate_priv(context, sourceText, 0, 0, &language, &translation);
00851 }
00852 if (language.isEmpty() || language == defaultLanguage()) {
00853 d->translate_priv(0, sourceText, 0, 0, &language, &translation);
00854 }
00855 }
00856
00857 if (language != defaultLanguage()) {
00858 return translation;
00859 }
00860
00861
00862 return QString();
00863 }
00864
00865 bool KLocale::nounDeclension() const
00866 {
00867 return d->nounDeclension;
00868 }
00869
00870 bool KLocale::dateMonthNamePossessive() const
00871 {
00872 return d->dateMonthNamePossessive;
00873 }
00874
00875 int KLocale::weekStartDay() const
00876 {
00877 return d->weekStartDay;
00878 }
00879
00880 int KLocale::workingWeekStartDay() const
00881 {
00882 return d->workingWeekStartDay;
00883 }
00884
00885 int KLocale::workingWeekEndDay() const
00886 {
00887 return d->workingWeekEndDay;
00888 }
00889
00890 int KLocale::weekDayOfPray() const
00891 {
00892 return d->weekDayOfPray;
00893 }
00894
00895
00896 QString KLocale::decimalSymbol() const
00897 {
00898 return d->decimalSymbol;
00899 }
00900
00901 QString KLocale::thousandsSeparator() const
00902 {
00903 return d->thousandsSeparator;
00904 }
00905
00906 QString KLocale::currencySymbol() const
00907 {
00908 return d->currencySymbol;
00909 }
00910
00911 QString KLocale::monetaryDecimalSymbol() const
00912 {
00913 return d->monetaryDecimalSymbol;
00914 }
00915
00916 QString KLocale::monetaryThousandsSeparator() const
00917 {
00918 return d->monetaryThousandsSeparator;
00919 }
00920
00921 QString KLocale::positiveSign() const
00922 {
00923 return d->positiveSign;
00924 }
00925
00926 QString KLocale::negativeSign() const
00927 {
00928 return d->negativeSign;
00929 }
00930
00931 int KLocale::fracDigits() const
00932 {
00933 return d->fracDigits;
00934 }
00935
00936 bool KLocale::positivePrefixCurrencySymbol() const
00937 {
00938 return d->positivePrefixCurrencySymbol;
00939 }
00940
00941 bool KLocale::negativePrefixCurrencySymbol() const
00942 {
00943 return d->negativePrefixCurrencySymbol;
00944 }
00945
00946 KLocale::SignPosition KLocale::positiveMonetarySignPosition() const
00947 {
00948 return d->positiveMonetarySignPosition;
00949 }
00950
00951 KLocale::SignPosition KLocale::negativeMonetarySignPosition() const
00952 {
00953 return d->negativeMonetarySignPosition;
00954 }
00955
00956 static inline void put_it_in( QChar *buffer, int& index, const QString &s )
00957 {
00958 for ( int l = 0; l < s.length(); l++ )
00959 buffer[index++] = s.at( l );
00960 }
00961
00962 static inline void put_it_in( QChar *buffer, int& index, int number )
00963 {
00964 buffer[index++] = number / 10 + '0';
00965 buffer[index++] = number % 10 + '0';
00966 }
00967
00968
00969 static void _insertSeparator(QString &str, const QString &separator,
00970 const QString &decimalSymbol)
00971 {
00972
00973 const int decimalSymbolPos = str.indexOf(decimalSymbol);
00974 const int start = decimalSymbolPos == -1 ? str.length() : decimalSymbolPos;
00975 for (int pos = start - 3; pos > 0; pos -= 3)
00976 str.insert(pos, separator);
00977 }
00978
00979 QString KLocale::formatMoney(double num,
00980 const QString & symbol,
00981 int precision) const
00982 {
00983
00984 QString currency = symbol.isNull()
00985 ? currencySymbol()
00986 : symbol;
00987 if (precision < 0) precision = fracDigits();
00988
00989
00990 bool neg = num < 0;
00991 QString res = QString::number(neg?-num:num, 'f', precision);
00992
00993
00994 res.replace(QChar('.'), monetaryDecimalSymbol());
00995
00996
00997 _insertSeparator(res, monetaryThousandsSeparator(), monetaryDecimalSymbol());
00998
00999
01000 int signpos = neg
01001 ? negativeMonetarySignPosition()
01002 : positiveMonetarySignPosition();
01003 QString sign = neg
01004 ? negativeSign()
01005 : positiveSign();
01006
01007 switch (signpos)
01008 {
01009 case ParensAround:
01010 res.prepend(QLatin1Char('('));
01011 res.append (QLatin1Char(')'));
01012 break;
01013 case BeforeQuantityMoney:
01014 res.prepend(sign);
01015 break;
01016 case AfterQuantityMoney:
01017 res.append(sign);
01018 break;
01019 case BeforeMoney:
01020 currency.prepend(sign);
01021 break;
01022 case AfterMoney:
01023 currency.append(sign);
01024 break;
01025 }
01026
01027 if (neg?negativePrefixCurrencySymbol():
01028 positivePrefixCurrencySymbol())
01029 {
01030 res.prepend(QLatin1Char(' '));
01031 res.prepend(currency);
01032 } else {
01033 res.append (QLatin1Char(' '));
01034 res.append (currency);
01035 }
01036
01037 return res;
01038 }
01039
01040
01041 QString KLocale::formatNumber(double num, int precision) const
01042 {
01043 if (precision == -1) precision = 2;
01044
01045 return formatNumber(QString::number(num, 'f', precision), false, 0);
01046 }
01047
01048 QString KLocale::formatLong(long num) const
01049 {
01050 return formatNumber((double)num, 0);
01051 }
01052
01053
01054
01055 static void _inc_by_one(QString &str, int position)
01056 {
01057 for (int i = position; i >= 0; i--)
01058 {
01059 char last_char = str[i].toLatin1();
01060 switch(last_char)
01061 {
01062 case '0':
01063 str[i] = '1';
01064 break;
01065 case '1':
01066 str[i] = '2';
01067 break;
01068 case '2':
01069 str[i] = '3';
01070 break;
01071 case '3':
01072 str[i] = '4';
01073 break;
01074 case '4':
01075 str[i] = '5';
01076 break;
01077 case '5':
01078 str[i] = '6';
01079 break;
01080 case '6':
01081 str[i] = '7';
01082 break;
01083 case '7':
01084 str[i] = '8';
01085 break;
01086 case '8':
01087 str[i] = '9';
01088 break;
01089 case '9':
01090 str[i] = '0';
01091 if (i == 0) str.prepend('1');
01092 continue;
01093 case '.':
01094 continue;
01095 }
01096 break;
01097 }
01098 }
01099
01100
01101 static void _round(QString &str, int precision)
01102 {
01103 int decimalSymbolPos = str.indexOf('.');
01104
01105 if (decimalSymbolPos == -1) {
01106 if (precision == 0) return;
01107 else if (precision > 0)
01108 {
01109 str.append('.');
01110 decimalSymbolPos = str.length() - 1;
01111 }
01112 }
01113
01114 str.reserve(str.length() + precision);
01115 for (int i = 0; i < precision; ++i)
01116 str.append('0');
01117
01118
01119 char last_char = str[decimalSymbolPos + precision + 1].toLatin1();
01120 switch (last_char)
01121 {
01122 case '0':
01123 case '1':
01124 case '2':
01125 case '3':
01126 case '4':
01127
01128 break;
01129 case '5':
01130 case '6':
01131 case '7':
01132 case '8':
01133 case '9':
01134 _inc_by_one(str, decimalSymbolPos + precision);
01135 break;
01136 default:
01137 break;
01138 }
01139
01140 decimalSymbolPos = str.indexOf('.');
01141 str.truncate(decimalSymbolPos + precision + 1);
01142
01143
01144 if (precision == 0) str = str.left(decimalSymbolPos);
01145
01146 str.squeeze();
01147 }
01148
01149 QString KLocale::formatNumber(const QString &numStr, bool round,
01150 int precision) const
01151 {
01152 QString tmpString = numStr;
01153 if (round && precision < 0)
01154 return numStr;
01155
01156
01157 const bool neg = (tmpString[0] == '-');
01158 if (neg || tmpString[0] == '+') tmpString.remove(0, 1);
01159
01160
01161
01162
01163 const int expPos = tmpString.indexOf('e');
01164 QString mantString = tmpString.left(expPos);
01165 QString expString;
01166 if (expPos > -1) {
01167 expString = tmpString.mid(expPos);
01168 if (expString.length() == 1)
01169 expString.clear();
01170 }
01171
01172
01173
01174 if (mantString.isEmpty() || !mantString[0].isDigit())
01175 mantString = "0";
01176
01177 if (round)
01178 _round(mantString, precision);
01179
01180
01181 mantString.replace(QChar('.'), decimalSymbol());
01182
01183
01184 _insertSeparator(mantString, thousandsSeparator(), decimalSymbol());
01185
01186
01187 mantString.prepend(neg?negativeSign():positiveSign());
01188
01189 return mantString + expString;
01190 }
01191
01192
01193
01194
01195
01196 QString KLocale::formatByteSize( double size ) const
01197 {
01198
01199
01200
01201
01202
01203
01204
01205
01206 QString s;
01207
01208 if ( size >= 1073741824.0 )
01209 {
01210 size /= 1073741824.0;
01211 if ( size > 1024 )
01212 s = i18n( "%1 TiB", formatNumber(size / 1024.0, 1));
01213 else
01214 s = i18n( "%1 GiB", formatNumber(size, 1));
01215 }
01216
01217 else if ( size >= 1048576.0 )
01218 {
01219 size /= 1048576.0;
01220 s = i18n( "%1 MiB", formatNumber(size, 1));
01221 }
01222
01223 else if ( size >= 1024.0 )
01224 {
01225 size /= 1024.0;
01226 s = i18n( "%1 KiB", formatNumber(size, 1));
01227 }
01228
01229 else if ( size > 0 )
01230 {
01231 s = i18n( "%1 B", formatNumber(size, 0));
01232 }
01233
01234 else
01235 {
01236 s = i18n( "0 B" );
01237 }
01238 return s;
01239 }
01240
01241 QString KLocale::formatDuration( unsigned long mSec) const
01242 {
01243 if( mSec >= 24*3600000) {
01244 return i18n( "%1 days", formatNumber( mSec/(24*3600000), 3));
01245 } else if(mSec >= 3600000)
01246 {
01247 return i18n( "%1 hours", formatNumber( mSec/3600000.0, 2));
01248 } else if(mSec >= 60000)
01249 {
01250 return i18n( "%1 minutes", formatNumber( mSec/60000.0, 2));
01251 } else if(mSec >= 1000)
01252 {
01253 return i18n( "%1 seconds", formatNumber( mSec/1000.0, 2));
01254 }
01255
01256 return i18n( "%1 milliseconds", formatNumber(mSec, 0));
01257 }
01258
01259 QString KLocalePrivate::formatSingleDuration( DurationType durationType, int n )
01260 {
01261 switch (durationType) {
01262 case DaysDurationType:
01263 return i18ncp("@item:intext", "1 day", "%1 days", n);
01264 case HoursDurationType:
01265 return i18ncp("@item:intext", "1 hour", "%1 hours", n);
01266 case MinutesDurationType:
01267 return i18ncp("@item:intext", "1 minute", "%1 minutes", n);
01268 case SecondsDurationType:
01269 return i18ncp("@item:intext", "1 second", "%1 seconds", n);
01270 }
01271 return QString();
01272 }
01273
01274 QString KLocale::prettyFormatDuration( unsigned long mSec ) const
01275 {
01276 unsigned long ms = mSec;
01277 int days = ms/(24*3600000);
01278 ms = ms%(24*3600000);
01279 int hours = ms/3600000;
01280 ms = ms%3600000;
01281 int minutes = ms/60000;
01282 ms = ms%60000;
01283 int seconds = qRound(ms/1000.0);
01284
01285
01286
01287 if (seconds == 60) {
01288 return prettyFormatDuration(mSec - ms + 60000);
01289 }
01290
01291 if (days && hours) {
01292 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", d->formatSingleDuration(KLocalePrivate::DaysDurationType, days), d->formatSingleDuration(KLocalePrivate::HoursDurationType, hours));
01293 } else if (days) {
01294 return d->formatSingleDuration(KLocalePrivate::DaysDurationType, days);
01295 } else if (hours && minutes) {
01296 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", d->formatSingleDuration(KLocalePrivate::HoursDurationType, hours), d->formatSingleDuration(KLocalePrivate::MinutesDurationType, minutes));
01297 } else if (hours) {
01298 return d->formatSingleDuration(KLocalePrivate::HoursDurationType, hours);
01299 } else if (minutes && seconds) {
01300 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", d->formatSingleDuration(KLocalePrivate::MinutesDurationType, minutes), d->formatSingleDuration(KLocalePrivate::SecondsDurationType, seconds));
01301 } else if (minutes) {
01302 return d->formatSingleDuration(KLocalePrivate::MinutesDurationType, minutes);
01303 } else {
01304 return d->formatSingleDuration(KLocalePrivate::SecondsDurationType, seconds);
01305 }
01306 }
01307
01308 QString KLocale::formatDate(const QDate &pDate, DateFormat format) const
01309 {
01310 if (format == FancyShortDate || format == FancyLongDate)
01311 {
01312 int days = pDate.daysTo(QDate::currentDate());
01313 if (days >= 0 && days < 7)
01314 return KLocalePrivate::fancyDate(this, pDate, days);
01315 format = (format == FancyShortDate) ? ShortDate : LongDate;
01316 }
01317 const QString rst = (format == ShortDate) ? dateFormatShort() : dateFormat();
01318
01319 QString buffer;
01320
01321 if ( ! pDate.isValid() ) return buffer;
01322
01323 bool escape = false;
01324
01325 int year = calendar()->year(pDate);
01326 int month = calendar()->month(pDate);
01327
01328 for ( int format_index = 0; format_index < rst.length(); ++format_index )
01329 {
01330 if ( !escape )
01331 {
01332 if ( rst.at( format_index ).unicode() == '%' )
01333 escape = true;
01334 else
01335 buffer.append(rst.at(format_index));
01336 }
01337 else
01338 {
01339 switch ( rst.at( format_index ).unicode() )
01340 {
01341 case '%':
01342 buffer.append(QLatin1Char('%'));
01343 break;
01344 case 'Y':
01345 buffer.append(calendar()->yearString(pDate, KCalendarSystem::LongFormat));
01346 break;
01347 case 'y':
01348 buffer.append(calendar()->yearString(pDate, KCalendarSystem::ShortFormat));
01349 break;
01350 case 'n':
01351 buffer.append(calendar()->monthString(pDate, KCalendarSystem::ShortFormat));
01352 break;
01353 case 'e':
01354 buffer.append(calendar()->dayString(pDate, KCalendarSystem::ShortFormat));
01355 break;
01356 case 'm':
01357 buffer.append(calendar()->monthString(pDate, KCalendarSystem::LongFormat));
01358 break;
01359 case 'b':
01360 if (d->dateMonthNamePossessive)
01361 buffer.append(calendar()->monthName(month, year, KCalendarSystem::ShortNamePossessive));
01362 else
01363 buffer.append(calendar()->monthName(month, year, KCalendarSystem::ShortName));
01364 break;
01365 case 'B':
01366 if (d->dateMonthNamePossessive)
01367 buffer.append(calendar()->monthName(month, year, KCalendarSystem::LongNamePossessive));
01368 else
01369 buffer.append(calendar()->monthName(month, year, KCalendarSystem::LongName));
01370 break;
01371 case 'd':
01372 buffer.append(calendar()->dayString(pDate, KCalendarSystem::LongFormat));
01373 break;
01374 case 'a':
01375 buffer.append(calendar()->weekDayName(pDate, KCalendarSystem::ShortDayName));
01376 break;
01377 case 'A':
01378 buffer.append(calendar()->weekDayName(pDate, KCalendarSystem::LongDayName));
01379 break;
01380 default:
01381 buffer.append(rst.at(format_index));
01382 break;
01383 }
01384 escape = false;
01385 }
01386 }
01387 return buffer;
01388 }
01389
01390 QString KLocalePrivate::fancyDate(const KLocale *locale, const QDate &date, int days)
01391 {
01392 switch (days)
01393 {
01394 case 0:
01395 return i18n("Today");
01396 case 1:
01397 return i18n("Yesterday");
01398 default:
01399 return locale->calendar()->weekDayName(date);
01400 }
01401 }
01402
01403 void KLocale::setMainCatalog(const char *catalog)
01404 {
01405 maincatalog = catalog;
01406 }
01407
01408 double KLocale::readNumber(const QString &_str, bool * ok) const
01409 {
01410 QString str = _str.trimmed();
01411 bool neg = str.indexOf(negativeSign()) == 0;
01412 if (neg)
01413 str.remove( 0, negativeSign().length() );
01414
01415
01416
01417
01418 QString exponentialPart;
01419 int EPos;
01420
01421 EPos = str.indexOf('E', 0, Qt::CaseInsensitive);
01422
01423 if (EPos != -1)
01424 {
01425 exponentialPart = str.mid(EPos);
01426 str = str.left(EPos);
01427 }
01428
01429 int pos = str.indexOf(decimalSymbol());
01430 QString major;
01431 QString minor;
01432 if ( pos == -1 )
01433 major = str;
01434 else
01435 {
01436 major = str.left(pos);
01437 minor = str.mid(pos + decimalSymbol().length());
01438 }
01439
01440
01441 int thlen = thousandsSeparator().length();
01442 int lastpos = 0;
01443 while ( ( pos = major.indexOf( thousandsSeparator() ) ) > 0 )
01444 {
01445
01446 int fromEnd = major.length() - pos;
01447 if ( fromEnd % (3+thlen) != 0
01448 || pos - lastpos > 3
01449 || pos == 0
01450 || (lastpos>0 && pos-lastpos!=3))
01451 {
01452 if (ok) *ok = false;
01453 return 0.0;
01454 }
01455
01456 lastpos = pos;
01457 major.remove( pos, thlen );
01458 }
01459 if (lastpos>0 && major.length()-lastpos!=3)
01460 {
01461 if (ok) *ok = false;
01462 return 0.0;
01463 }
01464
01465 QString tot;
01466 if (neg) tot = '-';
01467
01468 tot += major + '.' + minor + exponentialPart;
01469
01470 return tot.toDouble(ok);
01471 }
01472
01473 double KLocale::readMoney(const QString &_str, bool * ok) const
01474 {
01475 QString str = _str.trimmed();
01476 bool neg = false;
01477 bool currencyFound = false;
01478 QString symbol = currencySymbol();
01479
01480
01481 int pos = str.indexOf(symbol);
01482 if ( pos == 0 || pos == (int) str.length()-symbol.length() )
01483 {
01484 str.remove(pos,symbol.length());
01485 str = str.trimmed();
01486 currencyFound = true;
01487 }
01488 if (str.isEmpty())
01489 {
01490 if (ok) *ok = false;
01491 return 0;
01492 }
01493
01494
01495 if (negativeMonetarySignPosition() == ParensAround)
01496 {
01497 if (str[0] == '(' && str[str.length()-1] == ')')
01498 {
01499 neg = true;
01500 str.remove(str.length()-1,1);
01501 str.remove(0,1);
01502 }
01503 }
01504 else
01505 {
01506 int i1 = str.indexOf(negativeSign());
01507 if ( i1 == 0 || i1 == (int) str.length()-1 )
01508 {
01509 neg = true;
01510 str.remove(i1,negativeSign().length());
01511 }
01512 }
01513 if (neg) str = str.trimmed();
01514
01515
01516
01517 if ( !currencyFound )
01518 {
01519 pos = str.indexOf(symbol);
01520 if ( pos == 0 || pos == (int) str.length()-symbol.length() )
01521 {
01522 str.remove(pos,symbol.length());
01523 str = str.trimmed();
01524 }
01525 }
01526
01527
01528 pos = str.indexOf(monetaryDecimalSymbol());
01529 QString major;
01530 QString minior;
01531 if (pos == -1)
01532 major = str;
01533 else
01534 {
01535 major = str.left(pos);
01536 minior = str.mid(pos + monetaryDecimalSymbol().length());
01537 }
01538
01539
01540 int thlen = monetaryThousandsSeparator().length();
01541 int lastpos = 0;
01542 while ( ( pos = major.indexOf( monetaryThousandsSeparator() ) ) > 0 )
01543 {
01544
01545 int fromEnd = major.length() - pos;
01546 if ( fromEnd % (3+thlen) != 0
01547 || pos - lastpos > 3
01548 || pos == 0
01549 || (lastpos>0 && pos-lastpos!=3))
01550 {
01551 if (ok) *ok = false;
01552 return 0.0;
01553 }
01554 lastpos = pos;
01555 major.remove( pos, thlen );
01556 }
01557 if (lastpos>0 && major.length()-lastpos!=3)
01558 {
01559 if (ok) *ok = false;
01560 return 0.0;
01561 }
01562
01563 QString tot;
01564 if (neg) tot = '-';
01565 tot += major + '.' + minior;
01566 return tot.toDouble(ok);
01567 }
01568
01575 static int readInt(const QString &str, int &pos)
01576 {
01577 if (!str.at(pos).isDigit()) return -1;
01578 int result = 0;
01579 for (; str.length() > pos && str.at(pos).isDigit(); ++pos)
01580 {
01581 result *= 10;
01582 result += str.at(pos).digitValue();
01583 }
01584
01585 return result;
01586 }
01587
01588 QDate KLocale::readDate(const QString &intstr, bool* ok) const
01589 {
01590 QDate date;
01591 date = readDate(intstr, ShortFormat, ok);
01592 if (date.isValid()) return date;
01593 return readDate(intstr, NormalFormat, ok);
01594 }
01595
01596 QDate KLocale::readDate(const QString &intstr, ReadDateFlags flags, bool* ok) const
01597 {
01598 QString fmt = ((flags & ShortFormat) ? dateFormatShort() : dateFormat()).simplified();
01599 return readDate( intstr, fmt, ok );
01600 }
01601
01602 QDate KLocale::readDate(const QString &intstr, const QString &fmt, bool* ok) const
01603 {
01604
01605 QString str = intstr.simplified().toLower();
01606 int day = -1, month = -1;
01607
01608 int year = calendar()->year(QDate::currentDate());
01609 int strpos = 0;
01610 int fmtpos = 0;
01611
01612 int iLength;
01613
01614 bool error = false;
01615
01616 while (fmt.length() > fmtpos && str.length() > strpos && !error)
01617 {
01618
01619 QChar c = fmt.at(fmtpos++);
01620
01621 if (c != '%') {
01622 if (c.isSpace() && str.at(strpos).isSpace())
01623 strpos++;
01624 else if (c != str.at(strpos++))
01625 error = true;
01626 }
01627 else
01628 {
01629 int j;
01630
01631 if (str.length() > strpos && str.at(strpos).isSpace())
01632 strpos++;
01633
01634 c = fmt.at(fmtpos++);
01635 switch (c.unicode())
01636 {
01637 case 'a':
01638 case 'A':
01639
01640 error = true;
01641 j = 1;
01642 while (error && (j < 8)) {
01643 QString s;
01644 if ( c == 'a') {
01645 s = calendar()->weekDayName(j, KCalendarSystem::ShortDayName).toLower();
01646 } else {
01647 s = calendar()->weekDayName(j, KCalendarSystem::LongDayName).toLower();
01648 }
01649 int len = s.length();
01650 if (str.mid(strpos, len) == s)
01651 {
01652 strpos += len;
01653 error = false;
01654 }
01655 j++;
01656 }
01657 break;
01658 case 'b':
01659 case 'B':
01660
01661 error = true;
01662 if (d->dateMonthNamePossessive) {
01663 j = 1;
01664 while (error && (j < 13)) {
01665 QString s;
01666 if ( c == 'b' ) {
01667 s = calendar()->monthName(j, year, KCalendarSystem::ShortNamePossessive).toLower();
01668 } else {
01669 s = calendar()->monthName(j, year, KCalendarSystem::LongNamePossessive).toLower();
01670 }
01671 int len = s.length();
01672 if (str.mid(strpos, len) == s) {
01673 month = j;
01674 strpos += len;
01675 error = false;
01676 }
01677 j++;
01678 }
01679 }
01680 j = 1;
01681 while (error && (j < 13)) {
01682 QString s;
01683 if ( c == 'b' ) {
01684 s = calendar()->monthName(j, year, KCalendarSystem::ShortName).toLower();
01685 } else {
01686 s = calendar()->monthName(j, year, KCalendarSystem::LongName).toLower();
01687 }
01688 int len = s.length();
01689 if (str.mid(strpos, len) == s) {
01690 month = j;
01691 strpos += len;
01692 error = false;
01693 }
01694 j++;
01695 }
01696 break;
01697 case 'd':
01698 case 'e':
01699 day = calendar()->dayStringToInteger(str.mid(strpos), iLength);
01700 strpos += iLength;
01701
01702 error = iLength <= 0;
01703 break;
01704
01705 case 'n':
01706 case 'm':
01707 month = calendar()->monthStringToInteger(str.mid(strpos), iLength);
01708 strpos += iLength;
01709
01710 error = iLength <= 0;
01711 break;
01712
01713 case 'Y':
01714 case 'y':
01715 year = calendar()->yearStringToInteger(str.mid(strpos), iLength);
01716 strpos += iLength;
01717
01718 error = iLength <= 0;
01719 break;
01720 }
01721 }
01722 }
01723
01724
01725
01726 if ( fmt.length() > fmtpos || str.length() > strpos )
01727 {
01728 error = true;
01729 }
01730
01731
01732 if ( year != -1 && month != -1 && day != -1 && !error)
01733 {
01734 if (ok) *ok = true;
01735
01736 QDate result;
01737 calendar()->setYMD(result, year, month, day);
01738
01739 return result;
01740 }
01741
01742 if (ok) *ok = false;
01743 return QDate();
01744 }
01745
01746 QTime KLocale::readTime(const QString &intstr, bool *ok) const
01747 {
01748 QTime _time;
01749 _time = readTime(intstr, WithSeconds, ok);
01750 if (_time.isValid()) return _time;
01751 return readTime(intstr, WithoutSeconds, ok);
01752 }
01753
01754 QTime KLocale::readTime(const QString &intstr, ReadTimeFlags flags, bool *ok) const
01755 {
01756 QString str = intstr.simplified().toLower();
01757 QString Format = timeFormat().simplified();
01758 if (flags & WithoutSeconds)
01759 Format.remove(QRegExp(".%S"));
01760
01761 int hour = -1, minute = -1;
01762 int second = ( (flags & WithoutSeconds) == 0 ) ? -1 : 0;
01763 bool g_12h = false;
01764 bool pm = false;
01765 int strpos = 0;
01766 int Formatpos = 0;
01767
01768 while (Format.length() > Formatpos || str.length() > strpos)
01769 {
01770 if ( !(Format.length() > Formatpos && str.length() > strpos) ) goto error;
01771
01772 QChar c = Format.at(Formatpos++);
01773
01774 if (c != '%')
01775 {
01776 if (c.isSpace())
01777 strpos++;
01778 else if (c != str.at(strpos++))
01779 goto error;
01780 continue;
01781 }
01782
01783
01784 if (str.length() > strpos && str.at(strpos).isSpace())
01785 strpos++;
01786
01787 c = Format.at(Formatpos++);
01788 switch (c.unicode())
01789 {
01790 case 'p':
01791 {
01792 QString s;
01793 s = i18n("pm").toLower();
01794 int len = s.length();
01795 if (str.mid(strpos, len) == s)
01796 {
01797 pm = true;
01798 strpos += len;
01799 }
01800 else
01801 {
01802 s = i18n("am").toLower();
01803 len = s.length();
01804 if (str.mid(strpos, len) == s) {
01805 pm = false;
01806 strpos += len;
01807 }
01808 else
01809 goto error;
01810 }
01811 }
01812 break;
01813
01814 case 'k':
01815 case 'H':
01816 g_12h = false;
01817 hour = readInt(str, strpos);
01818 if (hour < 0 || hour > 23)
01819 goto error;
01820
01821 break;
01822
01823 case 'l':
01824 case 'I':
01825 g_12h = true;
01826 hour = readInt(str, strpos);
01827 if (hour < 1 || hour > 12)
01828 goto error;
01829
01830 break;
01831
01832 case 'M':
01833 minute = readInt(str, strpos);
01834 if (minute < 0 || minute > 59)
01835 goto error;
01836
01837 break;
01838
01839 case 'S':
01840 second = readInt(str, strpos);
01841 if (second < 0 || second > 59)
01842 goto error;
01843
01844 break;
01845 }
01846 }
01847 if (g_12h) {
01848 hour %= 12;
01849 if (pm) hour += 12;
01850 }
01851
01852 if (ok) *ok = true;
01853 return QTime(hour, minute, second);
01854
01855 error:
01856 if (ok) *ok = false;
01857 return QTime();
01858 }
01859
01860 QString KLocale::formatTime(const QTime &pTime, bool includeSecs, bool isDuration) const
01861 {
01862 const QString rst = timeFormat();
01863
01864
01865
01866 QChar *buffer = new QChar[rst.length() * 3 / 2 + 30];
01867
01868 int index = 0;
01869 bool escape = false;
01870 int number = 0;
01871
01872 for ( int format_index = 0; format_index < rst.length(); format_index++ )
01873 {
01874 if ( !escape )
01875 {
01876 if ( rst.at( format_index ).unicode() == '%' )
01877 escape = true;
01878 else
01879 buffer[index++] = rst.at( format_index );
01880 }
01881 else
01882 {
01883 switch ( rst.at( format_index ).unicode() )
01884 {
01885 case '%':
01886 buffer[index++] = '%';
01887 break;
01888 case 'H':
01889 put_it_in( buffer, index, pTime.hour() );
01890 break;
01891 case 'I':
01892 if ( isDuration )
01893 put_it_in( buffer, index, pTime.hour() );
01894 else
01895 put_it_in( buffer, index, ( pTime.hour() + 11) % 12 + 1 );
01896 break;
01897 case 'M':
01898 put_it_in( buffer, index, pTime.minute() );
01899 break;
01900 case 'S':
01901 if (includeSecs)
01902 put_it_in( buffer, index, pTime.second() );
01903 else if (index > 0) {
01904
01905 while(index > 0 && buffer[index-1].isSpace())
01906 --index;
01907
01908
01909 --index;
01910
01911 while(index > 0 && buffer[index-1].isSpace())
01912 --index;
01913 break;
01914 }
01915 break;
01916 case 'k':
01917 number = pTime.hour();
01918 case 'l':
01919
01920 if ( rst.at( format_index ).unicode() == 'l' )
01921 number = isDuration ? pTime.hour() : (pTime.hour() + 11) % 12 + 1;
01922 if ( number / 10 )
01923 buffer[index++] = number / 10 + '0';
01924 buffer[index++] = number % 10 + '0';
01925 break;
01926 case 'p':
01927 if ( !isDuration )
01928 {
01929 QString s;
01930 if ( pTime.hour() >= 12 )
01931 put_it_in( buffer, index, i18n("pm") );
01932 else
01933 put_it_in( buffer, index, i18n("am") );
01934 }
01935 break;
01936 default:
01937 buffer[index++] = rst.at( format_index );
01938 break;
01939 }
01940 escape = false;
01941 }
01942 }
01943 QString ret( buffer, index );
01944 delete [] buffer;
01945 if ( isDuration )
01946 return ret.trimmed();
01947 else
01948 return ret;
01949 }
01950
01951 bool KLocale::use12Clock() const
01952 {
01953 if ((timeFormat().contains(QString::fromLatin1("%I")) > 0) ||
01954 (timeFormat().contains(QString::fromLatin1("%l")) > 0))
01955 return true;
01956 else
01957 return false;
01958 }
01959
01960 QStringList KLocale::languageList() const
01961 {
01962 return d->languageList;
01963 }
01964
01965 QString KLocalePrivate::formatDateTime(const KLocale *locale, const QDateTime &dateTime,
01966 KLocale::DateFormat format, bool includeSeconds, int daysTo)
01967 {
01968 QString dateStr = (format == KLocale::FancyShortDate || format == KLocale::FancyLongDate)
01969 ? KLocalePrivate::fancyDate(locale, dateTime.date(), daysTo)
01970 : locale->formatDate(dateTime.date(), format);
01971 return i18nc("concatenation of dates and time", "%1 %2",
01972 dateStr, locale->formatTime(dateTime.time(), includeSeconds));
01973 }
01974
01975 QString KLocale::formatDateTime(const QDateTime &dateTime, DateFormat format,
01976 bool includeSeconds) const
01977 {
01978 QString dateStr;
01979 int days = -1;
01980 if (format == FancyShortDate || format == FancyLongDate)
01981 {
01982 QDateTime now = QDateTime::currentDateTime();
01983 days = dateTime.date().daysTo(now.date());
01984 if ((days == 0 && now.secsTo(dateTime) <= 3600)
01985 || (days > 0 && days < 7))
01986 ;
01987 else
01988 format = (format == FancyShortDate) ? ShortDate : LongDate;
01989 }
01990 return KLocalePrivate::formatDateTime(this, dateTime, format, includeSeconds, days);
01991 }
01992
01993 QString KLocale::formatDateTime(const KDateTime &dateTime, DateFormat format,
01994 DateTimeFormatOptions options) const
01995 {
01996 QString dt;
01997 if (dateTime.isDateOnly())
01998 dt = formatDate( dateTime.date(), format );
01999 else
02000 {
02001 int days = -1;
02002 if (format == FancyShortDate || format == FancyLongDate)
02003 {
02004
02005
02006 KDateTime now = KDateTime::currentDateTime(dateTime.timeSpec());
02007 days = dateTime.date().daysTo(now.date());
02008 if ((days == 0 && now.secsTo(dateTime) <= 3600)
02009 || (days > 0 && days < 7))
02010 ;
02011 else
02012 format = (format == FancyShortDate) ? ShortDate : LongDate;
02013 }
02014 dt = KLocalePrivate::formatDateTime(this, dateTime.dateTime(), format, (options & Seconds), days);
02015 }
02016 if (options & TimeZone)
02017 {
02018 QString tz;
02019 switch (dateTime.timeType())
02020 {
02021 case KDateTime::OffsetFromUTC:
02022 tz = i18n(dateTime.toString("%z").toUtf8());
02023 break;
02024 case KDateTime::UTC:
02025 case KDateTime::TimeZone:
02026 tz = i18n(dateTime.toString((format == ShortDate) ? "%Z" : "%:Z").toUtf8());
02027 break;
02028 case KDateTime::ClockTime:
02029 default:
02030 break;
02031 }
02032 return i18nc( "concatenation of date/time and time zone", "%1 %2", dt, tz );
02033 }
02034 else
02035 return dt;
02036 }
02037
02038 QString KLocale::langLookup(const QString &fname, const char *rtype)
02039 {
02040 QStringList search;
02041
02042
02043 const QStringList localDoc = KGlobal::dirs()->resourceDirs(rtype);
02044
02045
02046 for (int id=localDoc.count()-1; id >= 0; --id)
02047 {
02048 QStringList langs = KGlobal::locale()->languageList();
02049 langs.append( "en" );
02050 langs.removeAll( defaultLanguage() );
02051 Q_FOREACH(const QString &lang, langs)
02052 search.append(QString("%1%2/%3").arg(localDoc[id]).arg(lang).arg(fname));
02053 }
02054
02055
02056 Q_FOREACH (const QString &file, search)
02057 {
02058 kDebug(173) << "Looking for help in: " << file;
02059
02060 QFileInfo info(file);
02061 if (info.exists() && info.isFile() && info.isReadable())
02062 return file;
02063 }
02064
02065 return QString();
02066 }
02067
02068 bool KLocalePrivate::useDefaultLanguage() const
02069 {
02070 return language == KLocale::defaultLanguage();
02071 }
02072
02073 void KLocalePrivate::initEncoding()
02074 {
02075 codecForEncoding = 0;
02076
02077
02078 #if defined(HAVE_LANGINFO_H) && !defined(Q_OS_WIN)
02079
02080
02081
02082 QByteArray systemLocale = nl_langinfo(CODESET);
02083
02084 if (systemLocale == "ANSI_X3.4-1968")
02085 systemLocale = "ISO-8859-1";
02086
02087 QTextCodec* codec = QTextCodec::codecForName(systemLocale);
02088 if ( codec )
02089 setEncoding( codec->mibEnum() );
02090 #else
02091 setEncoding( QTextCodec::codecForLocale()->mibEnum() );
02092 #endif
02093
02094 if ( !codecForEncoding ) {
02095 kWarning() << "Cannot resolve system encoding, defaulting to ISO 8859-1.";
02096 const int mibDefault = 4;
02097 setEncoding(mibDefault);
02098 }
02099
02100 Q_ASSERT( codecForEncoding );
02101 }
02102
02103 void KLocalePrivate::initFileNameEncoding()
02104 {
02105
02106
02107 utf8FileEncoding = !qgetenv("KDE_UTF8_FILENAMES").isEmpty();
02108 if (utf8FileEncoding)
02109 {
02110 QFile::setEncodingFunction(KLocalePrivate::encodeFileNameUTF8);
02111 QFile::setDecodingFunction(KLocalePrivate::decodeFileNameUTF8);
02112 }
02113
02114
02115 }
02116
02117 QByteArray KLocalePrivate::encodeFileNameUTF8( const QString & fileName )
02118 {
02119 return fileName.toUtf8();
02120 }
02121
02122 QString KLocalePrivate::decodeFileNameUTF8( const QByteArray & localFileName )
02123 {
02124 return QString::fromUtf8(localFileName);
02125 }
02126
02127 void KLocale::setDateFormat(const QString & format)
02128 {
02129 d->dateFormat = format.trimmed();
02130 }
02131
02132 void KLocale::setDateFormatShort(const QString & format)
02133 {
02134 d->dateFormatShort = format.trimmed();
02135 }
02136
02137 void KLocale::setDateMonthNamePossessive(bool possessive)
02138 {
02139 d->dateMonthNamePossessive = possessive;
02140 }
02141
02142 void KLocale::setTimeFormat(const QString & format)
02143 {
02144 d->timeFormat = format.trimmed();
02145 }
02146
02147 void KLocale::setWeekStartDay(int day)
02148 {
02149 if (day >= 1 && day <= calendar()->daysInWeek(QDate()))
02150 d->weekStartDay = day;
02151 }
02152
02153 void KLocale::setWorkingWeekStartDay(int day)
02154 {
02155 if (day >= 1 && day <= calendar()->daysInWeek(QDate()))
02156 d->workingWeekStartDay = day;
02157 }
02158
02159 void KLocale::setWorkingWeekEndDay(int day)
02160 {
02161 if (day >= 1 && day <= calendar()->daysInWeek(QDate()))
02162 d->workingWeekEndDay = day;
02163 }
02164
02165 void KLocale::setWeekDayOfPray(int day)
02166 {
02167 if (day >= 0 && day <= calendar()->daysInWeek(QDate()))
02168 d->weekDayOfPray = day;
02169 }
02170
02171 QString KLocale::dateFormat() const
02172 {
02173 return d->dateFormat;
02174 }
02175
02176 QString KLocale::dateFormatShort() const
02177 {
02178 return d->dateFormatShort;
02179 }
02180
02181 QString KLocale::timeFormat() const
02182 {
02183 return d->timeFormat;
02184 }
02185
02186 void KLocale::setDecimalSymbol(const QString & symbol)
02187 {
02188 d->decimalSymbol = symbol.trimmed();
02189 }
02190
02191 void KLocale::setThousandsSeparator(const QString & separator)
02192 {
02193
02194 d->thousandsSeparator = separator;
02195 }
02196
02197 void KLocale::setPositiveSign(const QString & sign)
02198 {
02199 d->positiveSign = sign.trimmed();
02200 }
02201
02202 void KLocale::setNegativeSign(const QString & sign)
02203 {
02204 d->negativeSign = sign.trimmed();
02205 }
02206
02207 void KLocale::setPositiveMonetarySignPosition(SignPosition signpos)
02208 {
02209 d->positiveMonetarySignPosition = signpos;
02210 }
02211
02212 void KLocale::setNegativeMonetarySignPosition(SignPosition signpos)
02213 {
02214 d->negativeMonetarySignPosition = signpos;
02215 }
02216
02217 void KLocale::setPositivePrefixCurrencySymbol(bool prefix)
02218 {
02219 d->positivePrefixCurrencySymbol = prefix;
02220 }
02221
02222 void KLocale::setNegativePrefixCurrencySymbol(bool prefix)
02223 {
02224 d->negativePrefixCurrencySymbol = prefix;
02225 }
02226
02227 void KLocale::setFracDigits(int digits)
02228 {
02229 d->fracDigits = digits;
02230 }
02231
02232 void KLocale::setMonetaryThousandsSeparator(const QString & separator)
02233 {
02234
02235 d->monetaryThousandsSeparator = separator;
02236 }
02237
02238 void KLocale::setMonetaryDecimalSymbol(const QString & symbol)
02239 {
02240 d->monetaryDecimalSymbol = symbol.trimmed();
02241 }
02242
02243 void KLocale::setCurrencySymbol(const QString & symbol)
02244 {
02245 d->currencySymbol = symbol.trimmed();
02246 }
02247
02248 int KLocale::pageSize() const
02249 {
02250 return d->pageSize;
02251 }
02252
02253 void KLocale::setPageSize(int size)
02254 {
02255
02256 d->pageSize = size;
02257 }
02258
02259 KLocale::MeasureSystem KLocale::measureSystem() const
02260 {
02261 return d->measureSystem;
02262 }
02263
02264 void KLocale::setMeasureSystem(MeasureSystem value)
02265 {
02266 d->measureSystem = value;
02267 }
02268
02269 QString KLocale::defaultLanguage()
02270 {
02271 return QString::fromLatin1("en_US");
02272 }
02273
02274 QString KLocale::defaultCountry()
02275 {
02276 return QString::fromLatin1("C");
02277 }
02278
02279 bool KLocale::useTranscript() const
02280 {
02281 return d->useTranscript;
02282 }
02283
02284 const QByteArray KLocale::encoding() const
02285 {
02286 #ifdef Q_WS_WIN
02287 if (0==qstrcmp("System", codecForEncoding()->name()))
02288 {
02289
02290 strcpy(d->win32SystemEncoding, "cp ");
02291 if (GetLocaleInfoA( MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), SORT_DEFAULT),
02292 LOCALE_IDEFAULTANSICODEPAGE, d->win32SystemEncoding+3, sizeof(d->win32SystemEncoding)-3-1 ))
02293 {
02294 return d->win32SystemEncoding;
02295 }
02296 }
02297 #endif
02298 return codecForEncoding()->name();
02299 }
02300
02301 int KLocale::encodingMib() const
02302 {
02303 return codecForEncoding()->mibEnum();
02304 }
02305
02306 int KLocale::fileEncodingMib() const
02307 {
02308 if (d->utf8FileEncoding)
02309 return 106;
02310 return codecForEncoding()->mibEnum();
02311 }
02312
02313 QTextCodec * KLocale::codecForEncoding() const
02314 {
02315 return d->codecForEncoding;
02316 }
02317
02318 bool KLocale::setEncoding(int mibEnum)
02319 {
02320 return d->setEncoding(mibEnum);
02321 }
02322
02323 bool KLocalePrivate::setEncoding(int mibEnum)
02324 {
02325 QTextCodec * codec = QTextCodec::codecForMib(mibEnum);
02326 if (codec)
02327 codecForEncoding = codec;
02328
02329 return codec != 0;
02330 }
02331
02332 QStringList KLocale::allLanguagesList() const
02333 {
02334 if (!d->languages)
02335 d->languages = new KConfig("all_languages", KConfig::NoGlobals, "locale");
02336
02337 return d->languages->groupList();
02338 }
02339
02340 QString KLocale::languageCodeToName(const QString &language) const
02341 {
02342 if (!d->languages)
02343 d->languages = new KConfig("all_languages", KConfig::NoGlobals, "locale");
02344
02345 KConfigGroup cg(d->languages, language);
02346 return cg.readEntry("Name");
02347 }
02348
02349 QStringList KLocale::allCountriesList() const
02350 {
02351 QStringList countries;
02352 const QStringList paths = KGlobal::dirs()->findAllResources("locale", "l10n/*/entry.desktop");
02353 for(QStringList::ConstIterator it = paths.begin();
02354 it != paths.end(); ++it)
02355 {
02356 QString code = (*it).mid((*it).length()-16, 2);
02357 if (code != "/C")
02358 countries.append(code);
02359 }
02360 return countries;
02361 }
02362
02363 QString KLocale::countryCodeToName(const QString &country) const
02364 {
02365 QString countryName;
02366 QString entryFile = KStandardDirs::locate("locale", "l10n/"+country.toLower()+"/entry.desktop");
02367 if (!entryFile.isEmpty()) {
02368 KConfig cfg(entryFile);
02369 KConfigGroup cg(&cfg, "KCM Locale");
02370 countryName = cg.readEntry("Name");
02371 }
02372 return countryName;
02373 }
02374
02375 void KLocale::setCalendar(const QString & calType)
02376 {
02377 d->calendarType = calType;
02378
02379 delete d->calendar;
02380 d->calendar = 0;
02381 }
02382
02383 QString KLocale::calendarType() const
02384 {
02385 return d->calendarType;
02386 }
02387
02388 const KCalendarSystem * KLocale::calendar() const
02389 {
02390
02391 if ( !d->calendar )
02392 d->calendar = KCalendarSystem::create( d->calendarType, this );
02393
02394 return d->calendar;
02395 }
02396
02397 KLocale::KLocale(const KLocale & rhs) : d(new KLocalePrivate(*rhs.d))
02398 {
02399 d->languages = 0;
02400 d->calendar = 0;
02401 }
02402
02403 KLocale & KLocale::operator=(const KLocale & rhs)
02404 {
02405
02406 *d = *rhs.d;
02407 d->languages = 0;
02408 d->calendar = 0;
02409
02410 return *this;
02411 }
02412
02413 void KLocale::copyCatalogsTo(KLocale *locale)
02414 {
02415 locale->d->catalogNames = d->catalogNames;
02416 locale->d->updateCatalogs();
02417 }
02418
02419 QString KLocale::localizedFilePath(const QString &filePath) const
02420 {
02421
02422 if (d->useDefaultLanguage()) {
02423 return filePath;
02424 }
02425
02426
02427 QFileInfo fileInfo(filePath);
02428 QString locDirPath = fileInfo.path() + "/l10n";
02429 QFileInfo locDirInfo(locDirPath);
02430 if (!locDirInfo.isDir()) {
02431 return filePath;
02432 }
02433
02434
02435
02436 QString fileName = fileInfo.fileName();
02437 foreach (const QString &lang, d->languageList) {
02438
02439 if (lang == KLocale::defaultLanguage()) {
02440 return filePath;
02441 }
02442 QString locFilePath = locDirPath + '/' + lang + '/' + fileName;
02443 QFileInfo locFileInfo(locFilePath);
02444 if (locFileInfo.isFile() && locFileInfo.isReadable()) {
02445 return locFilePath;
02446 }
02447 }
02448
02449 return filePath;
02450 }
02451
02452 QString KLocale::removeAcceleratorMarker(const QString &label) const
02453 {
02454 return ::removeAcceleratorMarker(label);
02455 }