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