• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KDECore

klocale.cpp

Go to the documentation of this file.
00001 // -*- c-basic-offset: 2 -*-
00002 /* This file is part of the KDE libraries
00003    Copyright (c) 1997,2001 Stephan Kulow <coolo@kde.org>
00004    Copyright (c) 1999 Preston Brown <pbrown@kde.org>
00005    Copyright (c) 1999-2002 Hans Petter Bieker <bieker@kde.org>
00006    Copyright (c) 2002 Lukas Tinkl <lukas@kde.org>
00007    Copyright (C) 2007 Bernhard Loos <nhuh.put@web.de>
00008 
00009    This library is free software; you can redistribute it and/or
00010    modify it under the terms of the GNU Library General Public
00011    License as published by the Free Software Foundation; either
00012    version 2 of the License, or (at your option) any later version.
00013 
00014    This library is distributed in the hope that it will be useful,
00015    but WITHOUT ANY WARRANTY; without even the implied warranty of
00016    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017    Library General Public License for more details.
00018 
00019    You should have received a copy of the GNU Library General Public License
00020    along with this library; see the file COPYING.LIB.  If not, write to
00021    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00022    Boston, MA 02110-1301, USA.
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   // Numbers and money
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   // Date and time
00198   QString timeFormat;
00199   QString dateFormat;
00200   QString dateFormatShort;
00201   int weekStartDay;
00202   int workingWeekStartDay;
00203   int workingWeekEndDay;
00204   int weekDayOfPray;
00205 
00206   // Locale
00207   QString language;
00208   QString country;
00209 
00210   // Handling of translation catalogs
00211   QStringList languageList;
00212 
00213   QList<KCatalogName> catalogNames; // list of all catalogs (regardless of language)
00214   QList<KCatalog> catalogs; // list of all found catalogs, one instance per catalog name and language
00215   int numberOfSysCatalogs; // number of catalogs that each app draws from
00216   bool useTranscript; // indicates if scripted messages are to be executed
00217 
00218   // Misc
00219   QString encoding;
00220   QTextCodec * codecForEncoding;
00221   //KSharedConfig::Ptr config;
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]; //"cp " + lang ID
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   // Use the first non-null string.
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     // do not use insertCatalog here, that would already trigger updateCatalogs
00283     catalogNames.append(KCatalogName(mainCatalog));   // application catalog
00284 
00285     // catalogs from which each application can draw translations
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(); // evaluate this for all languages
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   // Set the country as specified by the KDE config or use default,
00308   // do not consider environment variables.
00309   if (country.isEmpty())
00310     country = cg.readEntry("Country");
00311   if (country.isEmpty())
00312       country = KLocale::defaultCountry();
00313 
00314   // Collect possible languages by decreasing priority.
00315   // The priority is as follows:
00316   // - KDE_LANG environment variable (can be a list)
00317   // - KDE configuration (can be a list)
00318   // - environment variables considered by gettext(3)
00319   // The environment variables are not considered if useEnv is false.
00320   QStringList list;
00321 
00322   if (!language.isEmpty())
00323       list.append(language);
00324 
00325   // Collect languages set by KDE_LANG.
00326   if (useEnv)
00327     getLanguagesFromVariable(list, "KDE_LANG");
00328 
00329   // Collect languages set by KDE config.
00330   QString languages(cg.readEntry("Language", QString()));
00331   if (!languages.isEmpty())
00332     list += languages.split(':');
00333 
00334   // Collect languages read from environment variables by gettext(3).
00335   QStringList rawList;
00336   if (useEnv) {
00337     // Collect by same order of priority as for gettext(3).
00338 
00339     // LANGUAGE should contain colon-separated list of exact language codes,
00340     // so add them directly.
00341     getLanguagesFromVariable(list, "LANGUAGE");
00342 
00343     // Other environment variables contain locale string, which should
00344     // be checked for all combinations yielding language codes.
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(); // fall back to the system language
00351 #endif
00352 
00353 #ifndef Q_WS_WIN
00354   if (useEnv) // Collect languages  - continued...
00355 #endif
00356   {
00357     // Process the raw list to create possible combinations.
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       // NOTE: The priority is tricky in case both ctry and modf are present.
00366       // Should really lang@modf be of higher priority than lang_ctry?
00367       // For at least one case (Serbian language), it is better this way.
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   // Send the list to filter for really present languages on the system.
00379   setLanguage(list);
00380 }
00381 
00382 void KLocalePrivate::initFormat(KConfig *config)
00383 {
00384   Q_ASSERT(config);
00385 
00386   //kDebug(173) << "KLocalePrivate::KLocalePrivate";
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   // Numeric
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   //kDebug(173) << "thousandsSeparator=" << thousandsSeparator;
00411 
00412   readConfigEntry("PositiveSign", "", positiveSign);
00413   readConfigEntry("NegativeSign", "-", negativeSign);
00414 
00415   // Monetary
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   // Date and time
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);                //default to Monday
00437   readConfigNumEntry("WorkingWeekStartDay", 1, workingWeekStartDay, int);  //default to Monday
00438   readConfigNumEntry("WorkingWeekEndDay", 5, workingWeekEndDay, int);      //default to Friday
00439   readConfigNumEntry("WeekDayOfPray", 7, weekDayOfPray, int);              //default to Sunday
00440 
00441   // other
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; // ### HPB Is this the correct place?
00449 
00450   readConfigEntry("Transcript", true, useTranscript);
00451 
00452   //Grammatical
00453   //Precedence here is l10n / i18n / config file
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   // Check if the file exists too??
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 ); // let us consider this language to be the most important one
00492 
00493   language = _language; // remember main language for shortcut evaluation
00494 
00495   // important when called from the outside and harmless when called before
00496   // populating the catalog name list
00497   updateCatalogs();
00498 
00499   initFormat(config);
00500 
00501   return true; // Maybe the mo-files for this language are empty, but in principle we can speak all languages
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   // This list might contain
00512   // 1) some empty strings that we have to eliminate
00513   // 2) duplicate entries like in de:fr:de, where we have to keep the first occurrence of a language in order
00514   //    to preserve the order of precenence of the user
00515   // 3) languages into which the application is not translated. For those languages we should not even load kdelibs.mo or kio.po.
00516   //    these languages have to be dropped. Otherwise we get strange side effects, e.g. with Hebrew:
00517   //    the right/left switch for languages that write from
00518   //    right to left (like Hebrew or Arabic) is set in kdelibs.mo. If you only have kdelibs.mo
00519   //    but nothing from appname.mo, you get a mostly English app with layout from right to left.
00520   //    That was considered to be a bug by the Hebrew translators.
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     // English should always be added as final possibility; this is important
00530     // for proper initialization of message text post-processors which are
00531     // needed for English too, like semantic to visual formatting, etc.
00532     list.append( KLocale::defaultLanguage() );
00533   }
00534 
00535   language = list.first(); // keep this for shortcut evaluations
00536 
00537   languageList = list; // keep this new list of languages to use
00538 
00539   // important when called from the outside and harmless when called before populating the
00540   // catalog name list
00541   updateCatalogs();
00542 
00543   return true; // we found something. Maybe it's only English, but we found something
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     // en_us is always "installed"
00559     return true;
00560   }
00561 
00562   if (maincatalog) {
00563     appName = QString::fromLatin1(maincatalog);
00564   }
00565 
00566   // Check for this language and possible transliteration fallbacks.
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   // In case there are several concatenated locale specifications,
00592   // truncate all but first.
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     // Insert new catalog just before system catalogs, to preserve the
00638     // lowest priority of system catalogs.
00639     d->catalogNames.insert(d->catalogNames.size() - d->numberOfSysCatalogs,
00640                            KCatalogName(catalog));
00641     d->updateCatalogs(); // evaluate the changed list and generate the necessary KCatalog objects
00642 }
00643 
00644 void KLocalePrivate::updateCatalogs( )
00645 {
00646   // some changes have occurred. Maybe we have learned or forgotten some languages.
00647   // Maybe the language precedence has changed.
00648   // Maybe we have learned or forgotten some catalog names.
00649 
00650   catalogs.clear();
00651 
00652   // Insert possible transliteration fallbacks after each set language.
00653   QStringList languageListFB;
00654   foreach (const QString &lang, languageList) {
00655     languageListFB += lang;
00656     languageListFB += KTranslit::fallbackList(lang);
00657   }
00658 
00659   // now iterate over all languages and all wanted catalog names and append or create them in the right order
00660   // the sequence must be e.g. nds/appname nds/kdelibs nds/kio de/appname de/kdelibs de/kio etc.
00661   // and not nds/appname de/appname nds/kdelibs de/kdelibs etc. Otherwise we would be in trouble with a language
00662   // sequende nds,en_US, de. In this case en_US must hide everything below in the language list.
00663   foreach ( const QString &lang, languageListFB )
00664     foreach ( const KCatalogName &name, catalogNames )
00665       // create and add catalog for this name and language if it exists
00666       if ( ! KCatalog::catalogLocaleDir( name.name, lang ).isEmpty() )
00667       {
00668         catalogs.append( KCatalog( name.name, lang ) );
00669         //kDebug(173) << "Catalog: " << name << ":" << lang;
00670       }
00671 
00672   // notify KLocalizedString of catalog update.
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();  // walk through the KCatalog instances and weed out everything we no longer need
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();  // walk through the KCatalog instances and adapt to the new order
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   // determine the fallback string
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   // shortcut evaluation if en_US is main language: do not consult the catalogs
00743   if ( useDefaultLanguage() )
00744     return;
00745 
00746   for ( QList<KCatalog>::ConstIterator it = catalogs.begin();
00747         it != catalogs.end();
00748         ++it )
00749   {
00750     // shortcut evaluation: once we have arrived at en_US (default language) we cannot consult
00751     // the catalog as it will not have an assiciated mo-file. For this default language we can
00752     // immediately pick the fallback string.
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       // we found it
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   // Qt's context is normally the name of the class of the method which makes
00806   // the tr(sourceText) call. However, it can also be manually supplied via
00807   // translate(context, sourceText) call.
00808   //
00809   // Qt's sourceText is the actual message displayed to the user.
00810   //
00811   // Qt's comment is an optional argument of tr() and translate(), like
00812   // tr(sourceText, comment) and translate(context, sourceText, comment).
00813   //
00814   // We handle this in the following way:
00815   //
00816   // If the comment is given, then it is considered gettext's msgctxt, so a
00817   // context call is made.
00818   //
00819   // If the comment is not given, but context is given, then we treat it as
00820   // msgctxt only if it was manually supplied (the one in translate()) -- but
00821   // we don't know this, so we first try a context call, and if translation
00822   // is not found, we fallback to ordinary call.
00823   //
00824   // If neither comment nor context are given, it's just an ordinary call
00825   // on sourceText.
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   // NOTE: Condition (language != defaultLanguage()) means that translation
00841   // was found, otherwise we got the original string back as translation.
00842 
00843   if (comment && comment[0]) {
00844     // Comment given, go for context call.
00845     d->translate_priv(comment, sourceText, 0, 0, &language, &translation);
00846   }
00847   else {
00848     // Comment not given, go for try-fallback with context.
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   // No proper translation found, return empty according to Qt's expectation.
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 // insert (thousands)-"separator"s into the non-fractional part of str
00969 static void _insertSeparator(QString &str, const QString &separator,
00970                  const QString &decimalSymbol)
00971 {
00972   // leave fractional part untouched
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   // some defaults
00984   QString currency = symbol.isNull()
00985     ? currencySymbol()
00986     : symbol;
00987   if (precision < 0) precision = fracDigits();
00988 
00989   // the number itself
00990   bool neg = num < 0;
00991   QString res = QString::number(neg?-num:num, 'f', precision);
00992 
00993   // Replace dot with locale decimal separator
00994   res.replace(QChar('.'), monetaryDecimalSymbol());
00995 
00996   // Insert the thousand separators
00997   _insertSeparator(res, monetaryThousandsSeparator(), monetaryDecimalSymbol());
00998 
00999   // set some variables we need later
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   // no need to round since QString::number does this for us
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 // increase the digit at 'position' by one
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 // Cut off if more digits in fractional part than 'precision'
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) // add dot if missing (and needed)
01108       {
01109     str.append('.');
01110     decimalSymbolPos = str.length() - 1;
01111       }
01112   }
01113   // fill up with more than enough zeroes (in case fractional part too short)
01114   str.reserve(str.length() + precision);
01115   for (int i = 0; i < precision; ++i)
01116     str.append('0');
01117 
01118   // Now decide whether to round up or down
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       // nothing to do, rounding down
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   // if precision == 0 delete also '.'
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   // Skip the sign (for now)
01157   const bool neg = (tmpString[0] == '-');
01158   if (neg || tmpString[0] == '+') tmpString.remove(0, 1);
01159 
01160   //kDebug(173)<<"tmpString:"<<tmpString;
01161 
01162   // Split off exponential part (including 'e'-symbol)
01163   const int expPos = tmpString.indexOf('e'); // -1 if not found
01164   QString mantString = tmpString.left(expPos); // entire string if no 'e' found
01165   QString expString;
01166   if (expPos > -1) {
01167     expString = tmpString.mid(expPos); // includes the 'e', or empty if no 'e'
01168     if (expString.length() == 1)
01169       expString.clear();
01170   }
01171 
01172   //kDebug(173)<<"mantString:"<<mantString;
01173   //kDebug(173)<<"expString:"<<expString;
01174   if (mantString.isEmpty() || !mantString[0].isDigit()) // invalid number
01175     mantString = "0";
01176 
01177   if (round)
01178     _round(mantString, precision);
01179 
01180   // Replace dot with locale decimal separator
01181   mantString.replace(QChar('.'), decimalSymbol());
01182 
01183   // Insert the thousand separators
01184   _insertSeparator(mantString, thousandsSeparator(), decimalSymbol());
01185 
01186   // How can we know where we should put the sign?
01187   mantString.prepend(neg?negativeSign():positiveSign());
01188 
01189   return mantString + expString;
01190 }
01191 
01192 // If someone wants the SI-standard prefixes kB/MB/GB/TB, I would recommend
01193 // a hidden kconfig option and getting the code from #57240 into the same
01194 // method, so that all KDE apps use the same unit, instead of letting each app decide.
01195 
01196 QString KLocale::formatByteSize( double size ) const
01197 {
01198     // Per IEC 60027-2
01199 
01200     // Binary prefixes
01201     //Tebi-byte             TiB             2^40    1,099,511,627,776 bytes
01202     //Gibi-byte             GiB             2^30    1,073,741,824 bytes
01203     //Mebi-byte             MiB             2^20    1,048,576 bytes
01204     //Kibi-byte             KiB             2^10    1,024 bytes
01205 
01206     QString s;
01207     // Gibi-byte
01208     if ( size >= 1073741824.0 )
01209     {
01210         size /= 1073741824.0;
01211         if ( size > 1024 ) // Tebi-byte
01212             s = i18n( "%1 TiB", formatNumber(size / 1024.0, 1));
01213         else
01214             s = i18n( "%1 GiB", formatNumber(size, 1));
01215     }
01216     // Mebi-byte
01217     else if ( size >= 1048576.0 )
01218     {
01219         size /= 1048576.0;
01220         s = i18n( "%1 MiB", formatNumber(size, 1));
01221     }
01222     // Kibi-byte
01223     else if ( size >= 1024.0 )
01224     {
01225         size /= 1024.0;
01226         s = i18n( "%1 KiB", formatNumber(size, 1));
01227     }
01228     // Just byte
01229     else if ( size > 0 )
01230     {
01231         s = i18n( "%1 B", formatNumber(size, 0));
01232     }
01233     // Nothing
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     // Handle correctly problematic case #1 (look at KLocaleTest::prettyFormatDuration()
01286     // at klocaletest.cpp)
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':  //Long year numeric
01345           buffer.append(calendar()->yearString(pDate, KCalendarSystem::LongFormat));
01346           break;
01347         case 'y':  //Short year numeric
01348           buffer.append(calendar()->yearString(pDate, KCalendarSystem::ShortFormat));
01349           break;
01350         case 'n':  //Short month numeric
01351               buffer.append(calendar()->monthString(pDate, KCalendarSystem::ShortFormat));
01352           break;
01353         case 'e':  //Short day numeric
01354               buffer.append(calendar()->dayString(pDate, KCalendarSystem::ShortFormat));
01355           break;
01356         case 'm':  //Long month numeric
01357               buffer.append(calendar()->monthString(pDate, KCalendarSystem::LongFormat));
01358           break;
01359         case 'b':  //Short month name
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':  //Long month name
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':  //Long day numeric
01372               buffer.append(calendar()->dayString(pDate, KCalendarSystem::LongFormat));
01373           break;
01374         case 'a':  //Short weekday name
01375           buffer.append(calendar()->weekDayName(pDate, KCalendarSystem::ShortDayName));
01376           break;
01377         case 'A':  //Long weekday name
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   /* will hold the scientific notation portion of the number.
01416      Example, with 2.34E+23, exponentialPart == "E+23"
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   // Remove thousand separators
01441   int thlen = thousandsSeparator().length();
01442   int lastpos = 0;
01443   while ( ( pos = major.indexOf( thousandsSeparator() ) ) > 0 )
01444   {
01445     // e.g. 12,,345,,678,,922 Acceptable positions (from the end) are 5, 10, 15... i.e. (3+thlen)*N
01446     int fromEnd = major.length() - pos;
01447     if ( fromEnd % (3+thlen) != 0 // Needs to be a multiple, otherwise it's an error
01448         || pos - lastpos > 3 // More than 3 digits between two separators -> error
01449         || pos == 0          // Can't start with a separator
01450         || (lastpos>0 && pos-lastpos!=3))   // Must have exactly 3 digits between two separators
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)   // Must have exactly 3 digits after the last separator
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   // First try removing currency symbol from either end
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   // Then try removing negative sign from either end
01494   // (with a special case for parenthesis)
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   // Finally try again for the currency symbol, if we didn't find
01516   // it already (because of the negative sign being in the way).
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   // And parse the rest as a number
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   // Remove thousand separators
01540   int thlen = monetaryThousandsSeparator().length();
01541   int lastpos = 0;
01542   while ( ( pos = major.indexOf( monetaryThousandsSeparator() ) ) > 0 )
01543   {
01544     // e.g. 12,,345,,678,,922 Acceptable positions (from the end) are 5, 10, 15... i.e. (3+thlen)*N
01545     int fromEnd = major.length() - pos;
01546     if ( fromEnd % (3+thlen) != 0 // Needs to be a multiple, otherwise it's an error
01547         || pos - lastpos > 3 // More than 3 digits between two separators -> error
01548         || pos == 0          // Can't start with a separator
01549         || (lastpos>0 && pos-lastpos!=3))   // Must have exactly 3 digits between two separators
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)   // Must have exactly 3 digits after the last separator
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   //kDebug(173) << "KLocale::readDate intstr=" << intstr << " fmt=" << fmt;
01605   QString str = intstr.simplified().toLower();
01606   int day = -1, month = -1;
01607   // allow the year to be omitted if not in the format
01608   int year = calendar()->year(QDate::currentDate());
01609   int strpos = 0;
01610   int fmtpos = 0;
01611 
01612   int iLength; // Temporary variable used when reading input
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       // remove space at the beginning
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     /* for a match, we should reach the end of both strings, not just one of
01725        them */
01726     if ( fmt.length() > fmtpos || str.length() > strpos )
01727     {
01728       error = true;
01729     }
01730 
01731     //kDebug(173) << "KLocale::readDate day=" << day << " month=" << month << " year=" << year;
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(); // invalid date
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; // don't require seconds
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       // remove space at the beginning
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(); // return invalid date if it didn't work
01858 }
01859 
01860 QString KLocale::formatTime(const QTime &pTime, bool includeSecs, bool isDuration) const
01861 {
01862   const QString rst = timeFormat();
01863 
01864   // only "pm/am" here can grow, the rest shrinks, but
01865   // I'm rather safe than sorry
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                   // remove spaces (#164813)
01905                   while(index > 0 && buffer[index-1].isSpace())
01906                     --index;
01907           // we remove the separator sign before the seconds and
01908           // assume that works everywhere
01909           --index;
01910                   // remove spaces (#164813)
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           // to share the code
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 ) // eliminate trailing-space due to " %p"
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)   // not more than an hour in the future
01985     ||  (days > 0 && days < 7))
01986       ;  // use fancy date format
01987     else
01988       format = (format == FancyShortDate) ? ShortDate : LongDate;  // fancy date not applicable
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       // Use the time specification (i.e. time zone, etc.) of 'dateTime' to
02005       // check whether it's less than a week ago.
02006       KDateTime now = KDateTime::currentDateTime(dateTime.timeSpec());
02007       days = dateTime.date().daysTo(now.date());
02008       if ((days == 0 && now.secsTo(dateTime) <= 3600)   // not more than an hour in the future
02009       ||  (days > 0 && days < 7))
02010         ;  // use fancy date format
02011       else
02012         format = (format == FancyShortDate) ? ShortDate : LongDate;  // fancy date not applicable
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   // assemble the local search paths
02043   const QStringList localDoc = KGlobal::dirs()->resourceDirs(rtype);
02044 
02045   // look up the different languages
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   // try to locate the file
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   // This all made more sense when we still had the EncodingEnum config key.
02078 #if defined(HAVE_LANGINFO_H) && !defined(Q_OS_WIN)
02079   // Qt since 4.2 always returns 'System' as codecForLocale and KDE (for example KEncodingFileDialog)
02080   // expects real encoding name. So on systems that have langinfo.h use nl_langinfo instead,
02081   // just like Qt compiled without iconv does. Windows already has its own workaround
02082   QByteArray systemLocale = nl_langinfo(CODESET);
02083 
02084   if (systemLocale == "ANSI_X3.4-1968") // means ascii, "C"; QTextCodec doesn't know, so avoid warning
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; // ISO 8859-1
02097       setEncoding(mibDefault);
02098     }
02099 
02100   Q_ASSERT( codecForEncoding );
02101 }
02102 
02103 void KLocalePrivate::initFileNameEncoding()
02104 {
02105   // If the following environment variable is set, assume all filenames
02106   // are in UTF-8 regardless of the current C locale.
02107   utf8FileEncoding = !qgetenv("KDE_UTF8_FILENAMES").isEmpty();
02108   if (utf8FileEncoding)
02109   {
02110     QFile::setEncodingFunction(KLocalePrivate::encodeFileNameUTF8);
02111     QFile::setDecodingFunction(KLocalePrivate::decodeFileNameUTF8);
02112   }
02113   // Otherwise, stay with QFile's default filename encoding functions
02114   // which, on Unix platforms, use the locale's codec.
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()))  // 0 = None
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   // allow spaces here
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   // allow spaces here
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   // #### check if it's in range??
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     //win32 returns "System" codec name here but KDE apps expect a real name:
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   // Check if it's the correct calendar?!?
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; // Don't copy languages
02400   d->calendar = 0; // Don't copy the calendar
02401 }
02402 
02403 KLocale & KLocale::operator=(const KLocale & rhs)
02404 {
02405   // the assignment operator works here
02406   *d = *rhs.d;
02407   d->languages = 0; // Don't copy languages
02408   d->calendar = 0; // Don't copy the calendar
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     // Stop here if the default language is primary.
02422     if (d->useDefaultLanguage()) {
02423         return filePath;
02424     }
02425 
02426     // Check if l10n sudir is present, stop if not.
02427     QFileInfo fileInfo(filePath);
02428     QString locDirPath = fileInfo.path() + "/l10n";
02429     QFileInfo locDirInfo(locDirPath);
02430     if (!locDirInfo.isDir()) {
02431         return filePath;
02432     }
02433 
02434     // Go through possible localized paths by priority of languages,
02435     // return first that exists.
02436     QString fileName = fileInfo.fileName();
02437     foreach (const QString &lang, d->languageList) {
02438         // Stop when the default language is reached.
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 }

KDECore

Skip menu "KDECore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal