• Skip to content
  • Skip to link menu
KDE 4.1 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 
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   // Numbers and money
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   // Date and time
00186   QString timeFormat;
00187   QString dateFormat;
00188   QString dateFormatShort;
00189   int weekStartDay;
00190 
00191   // Locale
00192   QString language;
00193   QString country;
00194 
00195   // Handling of translation catalogs
00196   QStringList languageList;
00197 
00198   QList<KCatalogName> catalogNames; // list of all catalogs (regardless of language)
00199   QList<KCatalog> catalogs; // list of all found catalogs, one instance per catalog name and language
00200   int numberOfSysCatalogs; // number of catalogs that each app draws from
00201   bool useTranscript; // indicates if scripted messages are to be executed
00202 
00203   // Misc
00204   QString encoding;
00205   QTextCodec * codecForEncoding;
00206   //KSharedConfig::Ptr config;
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]; //"cp " + lang ID
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   // Use the first non-null string.
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     // do not use insertCatalog here, that would already trigger updateCatalogs
00268     catalogNames.append(KCatalogName(mainCatalog));   // application catalog
00269 
00270     // catalogs from which each application can draw translations
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(); // evaluate this for all languages
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   // Set the country as specified by the KDE config or use default,
00293   // do not consider environment variables.
00294   if (country.isEmpty())
00295     country = cg.readEntry("Country");
00296   if (country.isEmpty())
00297       country = KLocale::defaultCountry();
00298 
00299   // Collect possible languages by decreasing priority.
00300   // The priority is as follows:
00301   // - KDE_LANG environment variable (can be a list)
00302   // - KDE configuration (can be a list)
00303   // - environment variables considered by gettext(3)
00304   // The environment variables are not considered if useEnv is false.
00305   QStringList list;
00306 
00307   if (!language.isEmpty())
00308       list.append(language);
00309 
00310   // Collect languages set by KDE_LANG.
00311   if (useEnv)
00312     getLanguagesFromVariable(list, "KDE_LANG");
00313 
00314   // Collect languages set by KDE config.
00315   QString languages(cg.readEntry("Language", QString()));
00316   if (!languages.isEmpty())
00317     list += languages.split(':');
00318 
00319   // Collect languages read from environment variables by gettext(3).
00320   QStringList rawList;
00321   if (useEnv) {
00322     // Collect by same order of priority as for gettext(3).
00323 
00324     // LANGUAGE should contain colon-separated list of exact language codes,
00325     // so add them directly.
00326     getLanguagesFromVariable(list, "LANGUAGE");
00327 
00328     // Other environment variables contain locale string, which should
00329     // be checked for all combinations yielding language codes.
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(); // fall back to the system language
00336 #endif
00337 
00338 #ifndef Q_WS_WIN
00339   if (useEnv) // Collect languages  - continued...
00340 #endif
00341   {
00342     // Process the raw list to create possible combinations.
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       // NOTE: The priority is tricky in case both ctry and modf are present.
00351       // Should really lang@modf be of higher priority than lang_ctry?
00352       // For at least one case (Serbian language), it is better this way.
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   // Send the list to filter for really present languages on the system.
00364   setLanguage(list);
00365 }
00366 
00367 void KLocalePrivate::initFormat(KConfig *config)
00368 {
00369   Q_ASSERT(config);
00370 
00371   //kDebug(173) << "KLocalePrivate::KLocalePrivate";
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   // Numeric
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   //kDebug(173) << "thousandsSeparator=" << thousandsSeparator;
00396 
00397   readConfigEntry("PositiveSign", "", positiveSign);
00398   readConfigEntry("NegativeSign", "-", negativeSign);
00399 
00400   // Monetary
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   // Date and time
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   // other
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; // ### HPB Is this the correct place?
00431 
00432   readConfigEntry("Transcript", true, useTranscript);
00433 
00434   //Grammatical
00435   //Precedence here is l10n / i18n / config file
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   // Check if the file exists too??
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 ); // let us consider this language to be the most important one
00474 
00475   language = _language; // remember main language for shortcut evaluation
00476 
00477   // important when called from the outside and harmless when called before
00478   // populating the catalog name list
00479   updateCatalogs();
00480 
00481   initFormat(config);
00482 
00483   return true; // Maybe the mo-files for this language are empty, but in principle we can speak all languages
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   // This list might contain
00494   // 1) some empty strings that we have to eliminate
00495   // 2) duplicate entries like in de:fr:de, where we have to keep the first occurrence of a language in order
00496   //    to preserve the order of precenence of the user
00497   // 3) languages into which the application is not translated. For those languages we should not even load kdelibs.mo or kio.po.
00498   //    these languages have to be dropped. Otherwise we get strange side effects, e.g. with Hebrew:
00499   //    the right/left switch for languages that write from
00500   //    right to left (like Hebrew or Arabic) is set in kdelibs.mo. If you only have kdelibs.mo
00501   //    but nothing from appname.mo, you get a mostly English app with layout from right to left.
00502   //    That was considered to be a bug by the Hebrew translators.
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     // English should always be added as final possibility; this is important
00512     // for proper initialization of message text post-processors which are
00513     // needed for English too, like semantic to visual formatting, etc.
00514     list.append( KLocale::defaultLanguage() );
00515   }
00516 
00517   language = list.first(); // keep this for shortcut evaluations
00518 
00519   languageList = list; // keep this new list of languages to use
00520 
00521   // important when called from the outside and harmless when called before populating the
00522   // catalog name list
00523   updateCatalogs();
00524 
00525   return true; // we found something. Maybe it's only English, but we found something
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     // en_us is always "installed"
00541     return true;
00542   }
00543 
00544   if (maincatalog) {
00545     appName = QString::fromLatin1(maincatalog);
00546   }
00547 
00548   // Check for this language and possible transliteration fallbacks.
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   // In case there are several concatenated locale specifications,
00574   // truncate all but first.
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     // Insert new catalog just before system catalogs, to preserve the
00620     // lowest priority of system catalogs.
00621     d->catalogNames.insert(d->catalogNames.size() - d->numberOfSysCatalogs,
00622                            KCatalogName(catalog));
00623     d->updateCatalogs(); // evaluate the changed list and generate the necessary KCatalog objects
00624 }
00625 
00626 void KLocalePrivate::updateCatalogs( )
00627 {
00628   // some changes have occurred. Maybe we have learned or forgotten some languages.
00629   // Maybe the language precedence has changed.
00630   // Maybe we have learned or forgotten some catalog names.
00631 
00632   catalogs.clear();
00633 
00634   // Insert possible transliteration fallbacks after each set language.
00635   QStringList languageListFB;
00636   foreach (const QString &lang, languageList) {
00637     languageListFB += lang;
00638     languageListFB += KTranslit::fallbackList(lang);
00639   }
00640 
00641   // now iterate over all languages and all wanted catalog names and append or create them in the right order
00642   // the sequence must be e.g. nds/appname nds/kdelibs nds/kio de/appname de/kdelibs de/kio etc.
00643   // and not nds/appname de/appname nds/kdelibs de/kdelibs etc. Otherwise we would be in trouble with a language
00644   // sequende nds,en_US, de. In this case en_US must hide everything below in the language list.
00645   foreach ( const QString &lang, languageListFB )
00646     foreach ( const KCatalogName &name, catalogNames )
00647       // create and add catalog for this name and language if it exists
00648       if ( ! KCatalog::catalogLocaleDir( name.name, lang ).isEmpty() )
00649       {
00650         catalogs.append( KCatalog( name.name, lang ) );
00651         //kDebug(173) << "Catalog: " << name << ":" << lang;
00652       }
00653 
00654   // notify KLocalizedString of catalog update.
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();  // walk through the KCatalog instances and weed out everything we no longer need
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();  // walk through the KCatalog instances and adapt to the new order
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   // determine the fallback string
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   // shortcut evaluation if en_US is main language: do not consult the catalogs
00725   if ( useDefaultLanguage() )
00726     return;
00727 
00728   for ( QList<KCatalog>::ConstIterator it = catalogs.begin();
00729         it != catalogs.end();
00730         ++it )
00731   {
00732     // shortcut evaluation: once we have arrived at en_US (default language) we cannot consult
00733     // the catalog as it will not have an assiciated mo-file. For this default language we can
00734     // immediately pick the fallback string.
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       // we found it
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   // Qt's context is normally the name of the class of the method which makes
00788   // the tr(sourceText) call. However, it can also be manually supplied via
00789   // translate(context, sourceText) call.
00790   //
00791   // Qt's sourceText is the actual message displayed to the user.
00792   //
00793   // Qt's comment is an optional argument of tr() and translate(), like
00794   // tr(sourceText, comment) and translate(context, sourceText, comment).
00795   //
00796   // We handle this in the following way:
00797   //
00798   // If the comment is given, then it is considered gettext's msgctxt, so a
00799   // context call is made.
00800   //
00801   // If the comment is not given, but context is given, then we treat it as
00802   // msgctxt only if it was manually supplied (the one in translate()) -- but
00803   // we don't know this, so we first try a context call, and if translation
00804   // is not found, we fallback to ordinary call.
00805   //
00806   // If neither comment nor context are given, it's just an ordinary call
00807   // on sourceText.
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   // NOTE: Condition (language != defaultLanguage()) means that translation
00823   // was found, otherwise we got the original string back as translation.
00824 
00825   if (comment && comment[0]) {
00826     // Comment given, go for context call.
00827     d->translate_priv(comment, sourceText, 0, 0, &language, &translation);
00828   }
00829   else {
00830     // Comment not given, go for try-fallback with context.
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   // No proper translation found, return empty according to Qt's expectation.
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 // insert (thousands)-"separator"s into the non-fractional part of str
00936 static void _insertSeparator(QString &str, const QString &separator,
00937                  const QString &decimalSymbol)
00938 {
00939   // leave fractional part untouched
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   // some defaults
00951   QString currency = symbol.isNull()
00952     ? currencySymbol()
00953     : symbol;
00954   if (precision < 0) precision = fracDigits();
00955 
00956   // the number itself
00957   bool neg = num < 0;
00958   QString res = QString::number(neg?-num:num, 'f', precision);
00959 
00960   // Replace dot with locale decimal separator
00961   res.replace(QChar('.'), monetaryDecimalSymbol());
00962 
00963   // Insert the thousand separators
00964   _insertSeparator(res, monetaryThousandsSeparator(), monetaryDecimalSymbol());
00965 
00966   // set some variables we need later
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   // no need to round since QString::number does this for us
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 // increase the digit at 'position' by one
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 // Cut off if more digits in fractional part than 'precision'
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) // add dot if missing (and needed)
01075       {
01076     str.append('.');
01077     decimalSymbolPos = str.length() - 1;
01078       }
01079 
01080   // fill up with more than enough zeroes (in case fractional part too short)
01081   str.reserve(str.length() + precision);
01082   for (int i = 0; i < precision; ++i)
01083     str.append('0');
01084 
01085   // Now decide whether to round up or down
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       // nothing to do, rounding down
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   // if precision == 0 delete also '.'
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   // Skip the sign (for now)
01124   const bool neg = (tmpString[0] == '-');
01125   if (neg || tmpString[0] == '+') tmpString.remove(0, 1);
01126 
01127   //kDebug(173)<<"tmpString:"<<tmpString;
01128 
01129   // Split off exponential part (including 'e'-symbol)
01130   const int expPos = tmpString.indexOf('e'); // -1 if not found
01131   QString mantString = tmpString.left(expPos); // entire string if no 'e' found
01132   QString expString;
01133   if (expPos > -1) {
01134     expString = tmpString.mid(expPos); // includes the 'e', or empty if no 'e'
01135     if (expString.length() == 1)
01136       expString.clear();
01137   }
01138 
01139   //kDebug(173)<<"mantString:"<<mantString;
01140   //kDebug(173)<<"expString:"<<expString;
01141   if (mantString.isEmpty() || !mantString[0].isDigit()) // invalid number
01142     mantString = "0";
01143 
01144   if (round)
01145     _round(mantString, precision);
01146 
01147   // Replace dot with locale decimal separator
01148   mantString.replace(QChar('.'), decimalSymbol());
01149 
01150   // Insert the thousand separators
01151   _insertSeparator(mantString, thousandsSeparator(), decimalSymbol());
01152 
01153   // How can we know where we should put the sign?
01154   mantString.prepend(neg?negativeSign():positiveSign());
01155 
01156   return mantString + expString;
01157 }
01158 
01159 // If someone wants the SI-standard prefixes kB/MB/GB/TB, I would recommend
01160 // a hidden kconfig option and getting the code from #57240 into the same
01161 // method, so that all KDE apps use the same unit, instead of letting each app decide.
01162 
01163 QString KLocale::formatByteSize( double size ) const
01164 {
01165     // Per IEC 60027-2
01166 
01167     // Binary prefixes
01168     //Tebi-byte             TiB             2^40    1,099,511,627,776 bytes
01169     //Gibi-byte             GiB             2^30    1,073,741,824 bytes
01170     //Mebi-byte             MiB             2^20    1,048,576 bytes
01171     //Kibi-byte             KiB             2^10    1,024 bytes
01172 
01173     QString s;
01174     // Gibi-byte
01175     if ( size >= 1073741824.0 )
01176     {
01177         size /= 1073741824.0;
01178         if ( size > 1024 ) // Tebi-byte
01179             s = i18n( "%1 TiB", formatNumber(size / 1024.0, 1));
01180         else
01181             s = i18n( "%1 GiB", formatNumber(size, 1));
01182     }
01183     // Mebi-byte
01184     else if ( size >= 1048576.0 )
01185     {
01186         size /= 1048576.0;
01187         s = i18n( "%1 MiB", formatNumber(size, 1));
01188     }
01189     // Kibi-byte
01190     else if ( size >= 1024.0 )
01191     {
01192         size /= 1024.0;
01193         s = i18n( "%1 KiB", formatNumber(size, 1));
01194     }
01195     // Just byte
01196     else if ( size > 0 )
01197     {
01198         s = i18n( "%1 B", formatNumber(size, 0));
01199     }
01200     // Nothing
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':  //Long year numeric
01263           buffer.append(calendar()->yearString(pDate, KCalendarSystem::LongFormat));
01264           break;
01265         case 'y':  //Short year numeric
01266           buffer.append(calendar()->yearString(pDate, KCalendarSystem::ShortFormat));
01267           break;
01268         case 'n':  //Short month numeric
01269               buffer.append(calendar()->monthString(pDate, KCalendarSystem::ShortFormat));
01270           break;
01271         case 'e':  //Short day numeric
01272               buffer.append(calendar()->dayString(pDate, KCalendarSystem::ShortFormat));
01273           break;
01274         case 'm':  //Long month numeric
01275               buffer.append(calendar()->monthString(pDate, KCalendarSystem::LongFormat));
01276           break;
01277         case 'b':  //Short month name
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':  //Long month name
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':  //Long day numeric
01290               buffer.append(calendar()->dayString(pDate, KCalendarSystem::LongFormat));
01291           break;
01292         case 'a':  //Short weekday name
01293           buffer.append(calendar()->weekDayName(pDate, KCalendarSystem::ShortDayName));
01294           break;
01295         case 'A':  //Long weekday name
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   /* will hold the scientific notation portion of the number.
01334      Example, with 2.34E+23, exponentialPart == "E+23"
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   // Remove thousand separators
01359   int thlen = thousandsSeparator().length();
01360   int lastpos = 0;
01361   while ( ( pos = major.indexOf( thousandsSeparator() ) ) > 0 )
01362   {
01363     // e.g. 12,,345,,678,,922 Acceptable positions (from the end) are 5, 10, 15... i.e. (3+thlen)*N
01364     int fromEnd = major.length() - pos;
01365     if ( fromEnd % (3+thlen) != 0 // Needs to be a multiple, otherwise it's an error
01366         || pos - lastpos > 3 // More than 3 digits between two separators -> error
01367         || pos == 0          // Can't start with a separator
01368         || (lastpos>0 && pos-lastpos!=3))   // Must have exactly 3 digits between two separators
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)   // Must have exactly 3 digits after the last separator
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   // First try removing currency symbol from either end
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   // Then try removing negative sign from either end
01412   // (with a special case for parenthesis)
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   // Finally try again for the currency symbol, if we didn't find
01434   // it already (because of the negative sign being in the way).
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   // And parse the rest as a number
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   // Remove thousand separators
01458   int thlen = monetaryThousandsSeparator().length();
01459   int lastpos = 0;
01460   while ( ( pos = major.indexOf( monetaryThousandsSeparator() ) ) > 0 )
01461   {
01462     // e.g. 12,,345,,678,,922 Acceptable positions (from the end) are 5, 10, 15... i.e. (3+thlen)*N
01463     int fromEnd = major.length() - pos;
01464     if ( fromEnd % (3+thlen) != 0 // Needs to be a multiple, otherwise it's an error
01465         || pos - lastpos > 3 // More than 3 digits between two separators -> error
01466         || pos == 0          // Can't start with a separator
01467         || (lastpos>0 && pos-lastpos!=3))   // Must have exactly 3 digits between two separators
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)   // Must have exactly 3 digits after the last separator
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   //kDebug(173) << "KLocale::readDate intstr=" << intstr << " fmt=" << fmt;
01523   QString str = intstr.simplified().toLower();
01524   int day = -1, month = -1;
01525   // allow the year to be omitted if not in the format
01526   int year = calendar()->year(QDate::currentDate());
01527   int strpos = 0;
01528   int fmtpos = 0;
01529 
01530   int iLength; // Temporary variable used when reading input
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       // remove space at the beginning
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     /* for a match, we should reach the end of both strings, not just one of
01643        them */
01644     if ( fmt.length() > fmtpos || str.length() > strpos )
01645     {
01646       error = true;
01647     }
01648 
01649     //kDebug(173) << "KLocale::readDate day=" << day << " month=" << month << " year=" << year;
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(); // invalid date
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; // don't require seconds
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       // remove space at the beginning
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(); // return invalid date if it didn't work
01776 }
01777 
01778 QString KLocale::formatTime(const QTime &pTime, bool includeSecs, bool isDuration) const
01779 {
01780   const QString rst = timeFormat();
01781 
01782   // only "pm/am" here can grow, the rest shrinks, but
01783   // I'm rather safe than sorry
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                   // remove spaces (#164813)
01823                   while(index > 0 && buffer[index-1].isSpace())
01824                     --index;
01825           // we remove the separator sign before the seconds and
01826           // assume that works everywhere
01827           --index;
01828                   // remove spaces (#164813)
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           // to share the code
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 ) // eliminate trailing-space due to " %p"
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)   // not more than an hour in the future
01903     ||  (days > 0 && days < 7))
01904       ;  // use fancy date format
01905     else
01906       format = (format == FancyShortDate) ? ShortDate : LongDate;  // fancy date not applicable
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       // Use the time specification (i.e. time zone, etc.) of 'dateTime' to
01923       // check whether it's less than a week ago.
01924       KDateTime now = KDateTime::currentDateTime(dateTime.timeSpec());
01925       days = dateTime.date().daysTo(now.date());
01926       if ((days == 0 && now.secsTo(dateTime) <= 3600)   // not more than an hour in the future
01927       ||  (days > 0 && days < 7))
01928         ;  // use fancy date format
01929       else
01930         format = (format == FancyShortDate) ? ShortDate : LongDate;  // fancy date not applicable
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   // assemble the local search paths
01961   const QStringList localDoc = KGlobal::dirs()->resourceDirs(rtype);
01962 
01963   // look up the different languages
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   // try to locate the file
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; // ISO 8859-1
01996   codecForEncoding = 0;
01997 
01998   // This all made more sense when we still had the EncodingEnum config key.
01999 #if defined(HAVE_LANGINFO_H) && !defined(Q_OS_WIN)
02000   // Qt since 4.2 always returns 'System' as codecForLocale and KDE (for example KEncodingFileDialog)
02001   // expects real encoding name. So on systems that have langinfo.h use nl_langinfo instead,
02002   // just like Qt compiled without iconv does. Windows already has its own workaround
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   // If the following environment variable is set, assume all filenames
02023   // are in UTF-8 regardless of the current C locale.
02024   utf8FileEncoding = !qgetenv("KDE_UTF8_FILENAMES").isEmpty();
02025   if (utf8FileEncoding)
02026   {
02027     QFile::setEncodingFunction(KLocalePrivate::encodeFileNameUTF8);
02028     QFile::setDecodingFunction(KLocalePrivate::decodeFileNameUTF8);
02029   }
02030   // Otherwise, stay with QFile's default filename encoding functions
02031   // which, on Unix platforms, use the locale's codec.
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; //Monday is default
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   // allow spaces here
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   // allow spaces here
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   // #### check if it's in range??
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     //win32 returns "System" codec name here but KDE apps expect a real name:
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   // Check if it's the correct calendar?!?
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; // Don't copy languages
02301   d->calendar = 0; // Don't copy the calendar
02302 }
02303 
02304 KLocale & KLocale::operator=(const KLocale & rhs)
02305 {
02306   // the assignment operator works here
02307   *d = *rhs.d;
02308   d->languages = 0; // Don't copy languages
02309   d->calendar = 0; // Don't copy the calendar
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     // Stop here if the default language is primary.
02323     if (d->useDefaultLanguage()) {
02324         return filePath;
02325     }
02326 
02327     // Check if l10n sudir is present, stop if not.
02328     QFileInfo fileInfo(filePath);
02329     QString locDirPath = fileInfo.path() + "/l10n";
02330     QFileInfo locDirInfo(locDirPath);
02331     if (!locDirInfo.isDir()) {
02332         return filePath;
02333     }
02334 
02335     // Go through possible localized paths by priority of languages,
02336     // return first that exists.
02337     QString fileName = fileInfo.fileName();
02338     foreach (const QString &lang, d->languageList) {
02339         // Stop when the default language is reached.
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 }

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
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.4
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