kdecore Library: klocale.cpp Source File (kdecore Library)

| # kdecore Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# klocale.cpp

    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
    00008    This library is free software; you can redistribute it and/or
    00009    modify it under the terms of the GNU Library General Public
    00010    License as published by the Free Software Foundation; either
    00011    version 2 of the License, or (at your option) any later version.
    00012
    00013    This library is distributed in the hope that it will be useful,
    00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
    00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00016    Library General Public License for more details.
    00017
    00018    You should have received a copy of the GNU Library General Public License
    00019    along with this library; see the file COPYING.LIB.  If not, write to
    00020    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    00021    Boston, MA 02111-1307, USA.
    00022 */
    00023
    00024 #include <config.h>
    00025
    00026 #include <stdlib.h> // getenv
    00027
    00028 #include <qtextcodec.h>
    00029 #include <qfile.h>
    00030 #include <qprinter.h>
    00031 #include <qdatetime.h>
    00032 #include <qfileinfo.h>
    00033 #include <qregexp.h>
    00034
    00035 #include "kcatalogue.h"
    00036 #include "kglobal.h"
    00037 #include "kstandarddirs.h"
    00038 #include "ksimpleconfig.h"
    00039 #include "kinstance.h"
    00040 #include "kconfig.h"
    00041 #include "kdebug.h"
    00042 #include "kcalendarsystem.h"
    00043 #include "kcalendarsystemfactory.h"
    00044 #include "klocale.h"
    00045
    00046 static const char * const SYSTEM_MESSAGES = "kdelibs";
    00047
    00048 static const char *maincatalogue = 0;
    00049
    00050 class KLocalePrivate
    00051 {
    00052 public:
    00053   int weekStartDay;
    00054   bool nounDeclension;
    00055   bool dateMonthNamePossessive;
    00056   QStringList languageList;
    00057   QStringList catalogNames; // list of all catalogs (regardless of language)
    00058   QValueList<KCatalogue> catalogues; // list of all loaded catalogs, contains one instance per catalog name and language
    00059   QString encoding;
    00060   QTextCodec * codecForEncoding;
    00061   KConfig * config;
    00062   bool formatInited;
    00063   int /*QPrinter::PageSize*/ pageSize;
    00064   KLocale::MeasureSystem measureSystem;
    00065   QStringList langTwoAlpha;
    00066   KConfig *languages;
    00067
    00068   QString calendarType;
    00069   KCalendarSystem * calendar;
    00070   bool utf8FileEncoding;
    00071   QString appName;
    00072 };
    00073
    00074 static KLocale *this_klocale = 0;
    00075
    00076 KLocale::KLocale( const QString & catalog, KConfig * config )
    00077 {
    00078   d = new KLocalePrivate;
    00079   d->config = config;
    00080   d->languages = 0;
    00081   d->calendar = 0;
    00082   d->formatInited = false;
    00083
    00084   initEncoding(0);
    00085   initFileNameEncoding(0);
    00086
    00087   KConfig *cfg = d->config;
    00088   this_klocale = this;
    00089   if (!cfg) cfg = KGlobal::instance()->config();
    00090   this_klocale = 0;
    00091   Q_ASSERT( cfg );
    00092
    00093   d->appName = catalog;
    00094   initLanguageList( cfg, config == 0);
    00095   initMainCatalogues(catalog);
    00096 }
    00097
    00098 QString KLocale::_initLanguage(KConfigBase *config)
    00099 {
    00100   if (this_klocale)
    00101   {
    00102      // ### HPB Why this cast??
    00103      this_klocale->initLanguageList((KConfig *) config, true);
    00104      // todo: adapt current catalog list: remove unused languages, insert main catalogs, if not already found
    00105      return this_klocale->language();
    00106   }
    00107   return QString::null;
    00108 }
    00109
    00110 void KLocale::initMainCatalogues(const QString & catalog)
    00111 {
    00112   // Use the first non-null string.
    00113   QString mainCatalogue = catalog;
    00114   if (maincatalogue)
    00115     mainCatalogue = QString::fromLatin1(maincatalogue);
    00116
    00117   if (mainCatalogue.isEmpty()) {
    00118     kdDebug(173) << "KLocale instance created called without valid "
    00119                  << "catalog! Give an argument or call setMainCatalogue "
    00120                  << "before init" << endl;
    00121   }
    00122   else {
    00123     // do not use insertCatalogue here, that would already trigger updateCatalogs
    00124     d->catalogNames.append( mainCatalogue );   // application catalog
    00125     d->catalogNames.append( SYSTEM_MESSAGES ); // always include kdelibs.mo
    00126     d->catalogNames.append( "kio" );            // always include kio.mo
    00127     updateCatalogues(); // evaluate this for all languages
    00128   }
    00129 }
    00130
    00131 void KLocale::initLanguageList(KConfig * config, bool useEnv)
    00132 {
    00133   KConfigGroupSaver saver(config, "Locale");
    00134
    00135   m_country = config->readEntry( "Country" );
    00136   if ( m_country.isEmpty() )
    00137     m_country = defaultCountry();
    00138
    00139   // Reset the list and add the new languages
    00140   QStringList languageList;
    00141   if ( useEnv )
    00142     languageList += QStringList::split
    00143       (':', QFile::decodeName( ::getenv("KDE_LANG") ));
    00144
    00145   languageList += config->readListEntry("Language", ':');
    00146
    00147   // same order as setlocale use
    00148   if ( useEnv )
    00149     {
    00150       // HPB: Only run splitLocale on the environment variables..
    00151       QStringList langs;
    00152
    00153       langs << QFile::decodeName( ::getenv("LC_ALL") );
    00154       langs << QFile::decodeName( ::getenv("LC_MESSAGES") );
    00155       langs << QFile::decodeName( ::getenv("LANG") );
    00156
    00157       for ( QStringList::Iterator it = langs.begin();
    00158         it != langs.end();
    00159         ++it )
    00160     {
    00161       QString ln, ct, chrset;
    00162       splitLocale(*it, ln, ct, chrset);
    00163
    00164       if (!ct.isEmpty()) {
    00165         langs.insert(it, ln + '_' + ct);
    00166         if (!chrset.isEmpty())
    00167           langs.insert(it, ln + '_' + ct + '.' + chrset);
    00168       }
    00169
    00170           langs.insert(it, ln);
    00171     }
    00172
    00173       languageList += langs;
    00174     }
    00175
    00176   // now we have a language list -- let's use the first OK language
    00177   setLanguage( languageList );
    00178 }
    00179
    00180 void KLocale::initPluralTypes()
    00181 {
    00182   for ( QValueList<KCatalogue>::Iterator it = d->catalogues.begin();
    00183     it != d->catalogues.end();
    00184     ++it )
    00185   {
    00186     QString language = (*it).language();
    00187     int pt = pluralType( language );
    00188     (*it).setPluralType( pt );
    00189   }
    00190 }
    00191
    00192
    00193 int KLocale::pluralType( const QString & language )
    00194 {
    00195   for ( QValueList<KCatalogue>::ConstIterator it = d->catalogues.begin();
    00196     it != d->catalogues.end();
    00197     ++it )
    00198   {
    00199     if ( ((*it).name() == SYSTEM_MESSAGES ) && ((*it).language() == language )) {
    00200       return pluralType( *it );
    00201     }
    00202   }
    00203   // kdelibs.mo does not seem to exist for this language
    00204   return -1;
    00205 }
    00206
    00207 int KLocale::pluralType( const KCatalogue& catalog )
    00208 {
    00209     const char* pluralFormString =
    00210     I18N_NOOP("_: Dear translator, please do not translate this string "
    00211       "in any form, but pick the _right_ value out of "
    00212       "NoPlural/TwoForms/French... If not sure what to do mail "
    00213       "thd@kde.org and coolo@kde.org, they will tell you. "
    00214       "Better leave that out if unsure, the programs will "
    00215       "crash!!\nDefinition of PluralForm - to be set by the "
    00216       "translator of kdelibs.po");
    00217     QString pf (catalog.translate( pluralFormString));
    00218     if ( pf.isEmpty() ) {
    00219       return -1;
    00220     }
    00221     else if ( pf == "NoPlural" )
    00222       return 0;
    00223     else if ( pf == "TwoForms" )
    00224       return 1;
    00225     else if ( pf == "French" )
    00226       return 2;
    00227     else if ( pf == "OneTwoRest" )
    00228       return 3;
    00229     else if ( pf == "Russian" )
    00230       return 4;
    00231     else if ( pf == "Polish" )
    00232       return 5;
    00233     else if ( pf == "Slovenian" )
    00234       return 6;
    00235     else if ( pf == "Lithuanian" )
    00236       return 7;
    00237     else if ( pf == "Czech" )
    00238       return 8;
    00239     else if ( pf == "Slovak" )
    00240       return 9;
    00241     else if ( pf == "Maltese" )
    00242       return 10;
    00243     else if ( pf == "Arabic" )
    00244       return 11;
    00245     else if ( pf == "Balcan" )
    00246       return 12;
    00247     else if ( pf == "Macedonian" )
    00248       return 13;
    00249     else if ( pf == "Gaeilge" )
    00250         return 14;
    00251     else {
    00252       kdWarning(173) << "Definition of PluralForm is none of "
    00253                << "NoPlural/"
    00254                << "TwoForms/"
    00255                << "French/"
    00256                << "OneTwoRest/"
    00257                << "Russian/"
    00258                << "Polish/"
    00259                << "Slovenian/"
    00260                << "Lithuanian/"
    00261                << "Czech/"
    00262                << "Slovak/"
    00263                << "Arabic/"
    00264                << "Balcan/"
    00265                << "Macedonian/"
    00266                << "Gaeilge/"
    00267                << "Maltese: " << pf << endl;
    00268       exit(1);
    00269     }
    00270 }
    00271
    00272 void KLocale::doFormatInit() const
    00273 {
    00274   if ( d->formatInited ) return;
    00275
    00276   KLocale * that = const_cast<KLocale *>(this);
    00277   that->initFormat();
    00278
    00279   d->formatInited = true;
    00280 }
    00281
    00282 void KLocale::initFormat()
    00283 {
    00284   KConfig *config = d->config;
    00285   if (!config) config = KGlobal::instance()->config();
    00286   Q_ASSERT( config );
    00287
    00288   kdDebug(173) << "KLocale::initFormat" << endl;
    00289
    00290   // make sure the config files are read using the correct locale
    00291   // ### Why not add a KConfigBase::setLocale( const KLocale * )?
    00292   // ### Then we could remove this hack
    00293   KLocale *lsave = KGlobal::_locale;
    00294   KGlobal::_locale = this;
    00295
    00296   KConfigGroupSaver saver(config, "Locale");
    00297
    00298   KSimpleConfig entry(locate("locale",
    00299                              QString::fromLatin1("l10n/%1/entry.desktop")
    00300                              .arg(m_country)), true);
    00301   entry.setGroup("KCM Locale");
    00302
    00303   // Numeric
    00304 #define readConfigEntry(key, default, save) \
    00305   save = entry.readEntry(key, QString::fromLatin1(default)); \
    00306   save = config->readEntry(key, save);
    00307
    00308 #define readConfigNumEntry(key, default, save, type) \
    00309   save = (type)entry.readNumEntry(key, default); \
    00310   save = (type)config->readNumEntry(key, save);
    00311
    00312 #define readConfigBoolEntry(key, default, save) \
    00313   save = entry.readBoolEntry(key, default); \
    00314   save = config->readBoolEntry(key, save);
    00315
    00316   readConfigEntry("DecimalSymbol", ".", m_decimalSymbol);
    00317   readConfigEntry("ThousandsSeparator", ",", m_thousandsSeparator);
    00318   m_thousandsSeparator.replace( QString::fromLatin1("$0"), QString::null );
    00319   //kdDebug(173) << "m_thousandsSeparator=" << m_thousandsSeparator << endl;
    00320
    00321   readConfigEntry("PositiveSign", "", m_positiveSign);
    00322   readConfigEntry("NegativeSign", "-", m_negativeSign);
    00323
    00324   // Monetary
    00325   readConfigEntry("CurrencySymbol", "$", m_currencySymbol);
    00326   readConfigEntry("MonetaryDecimalSymbol", ".", m_monetaryDecimalSymbol);
    00327   readConfigEntry("MonetaryThousandsSeparator", ",",
    00328           m_monetaryThousandsSeparator);
    00329   m_monetaryThousandsSeparator.replace(QString::fromLatin1("$0"), QString::null);
    00330
    00331   readConfigNumEntry("FracDigits", 2, m_fracDigits, int);
    00332   readConfigBoolEntry("PositivePrefixCurrencySymbol", true,
    00333               m_positivePrefixCurrencySymbol);
    00334   readConfigBoolEntry("NegativePrefixCurrencySymbol", true,
    00335               m_negativePrefixCurrencySymbol);
    00336   readConfigNumEntry("PositiveMonetarySignPosition", (int)BeforeQuantityMoney,
    00337              m_positiveMonetarySignPosition, SignPosition);
    00338   readConfigNumEntry("NegativeMonetarySignPosition", (int)ParensAround,
    00339              m_negativeMonetarySignPosition, SignPosition);
    00340
    00341
    00342   // Date and time
    00343   readConfigEntry("TimeFormat", "%H:%M:%S", m_timeFormat);
    00344   readConfigEntry("DateFormat", "%A %d %B %Y", m_dateFormat);
    00345   readConfigEntry("DateFormatShort", "%Y-%m-%d", m_dateFormatShort);
    00346   readConfigNumEntry("WeekStartDay", 1, d->weekStartDay, int);
    00347
    00348   // other
    00349   readConfigNumEntry("PageSize", (int)QPrinter::A4, d->pageSize, int);
    00350   readConfigNumEntry("MeasureSystem", (int)Metric, d->measureSystem,
    00351              MeasureSystem);
    00352   readConfigEntry("CalendarSystem", "gregorian", d->calendarType);
    00353   delete d->calendar;
    00354   d->calendar = 0; // ### HPB Is this the correct place?
    00355
    00356   //Grammatical
    00357   //Precedence here is l10n / i18n / config file
    00358   KSimpleConfig language(locate("locale",
    00359                     QString::fromLatin1("%1/entry.desktop")
    00360                                 .arg(m_language)), true);
    00361   language.setGroup("KCM Locale");
    00362 #define read3ConfigBoolEntry(key, default, save) \
    00363   save = entry.readBoolEntry(key, default); \
    00364   save = language.readBoolEntry(key, save); \
    00365   save = config->readBoolEntry(key, save);
    00366
    00367   read3ConfigBoolEntry("NounDeclension", false, d->nounDeclension);
    00368   read3ConfigBoolEntry("DateMonthNamePossessive", false,
    00369                d->dateMonthNamePossessive);
    00370
    00371   // end of hack
    00372   KGlobal::_locale = lsave;
    00373 }
    00374
    00375 bool KLocale::setCountry(const QString & country)
    00376 {
    00377   // Check if the file exists too??
    00378   if ( country.isEmpty() )
    00379     return false;
    00380
    00381   m_country = country;
    00382
    00383   d->formatInited = false;
    00384
    00385   return true;
    00386 }
    00387
    00388 QString KLocale::catalogueFileName(const QString & language,
    00389                    const KCatalogue & catalog)
    00390 {
    00391   QString path = QString::fromLatin1("%1/LC_MESSAGES/%2.mo")
    00392     .arg( language )
    00393     .arg( catalog.name() );
    00394
    00395   return locate( "locale", path );
    00396 }
    00397
    00398 bool KLocale::setLanguage(const QString & language)
    00399 {
    00400   if ( d->languageList.contains( language ) ) {
    00401      d->languageList.remove( language );
    00402   }
    00403   d->languageList.prepend( language ); // let us consider this language to be the most important one
    00404
    00405   m_language = language; // remember main language for shortcut evaluation
    00406
    00407   // important when called from the outside and harmless when called before populating the
    00408   // catalog name list
    00409   updateCatalogues();
    00410
    00411   d->formatInited = false;
    00412
    00413   return true; // Maybe the mo-files for this language are empty, but in principle we can speak all languages
    00414 }
    00415
    00416 bool KLocale::setLanguage(const QStringList & languages)
    00417 {
    00418   QStringList languageList( languages );
    00419   // This list might contain
    00420   // 1) some empty strings that we have to eliminate
    00421   // 2) duplicate entries like in de:fr:de, where we have to keep the first occurrance of a language in order
    00422   //    to preserve the order of precenence of the user => iterate backwards
    00423   // 3) languages into which the application is not translated. For those languages we should not even load kdelibs.mo or kio.po.
    00424   //    these langugage have to be dropped. Otherwise we get strange side effects, e.g. with Hebrew:
    00425   //    the right/left switch for languages that write from
    00426   //    right to left (like Hebrew or Arabic) is set in kdelibs.mo. If you only have kdelibs.mo
    00427   //    but nothing from appname.mo, you get a mostly English app with layout from right to left.
    00428   //    That was considered to be a bug by the Hebrew translators.
    00429   for( QStringList::Iterator it = languageList.fromLast();
    00430     it != languageList.begin(); --it )
    00431   {
    00432     // kdDebug() << "checking " << (*it) << endl;
    00433     bool bIsTranslated = isApplicationTranslatedInto( *it );
    00434     if ( languageList.contains(*it) > 1 || (*it).isEmpty() || (!bIsTranslated) ) {
    00435       // kdDebug() << "removing " << (*it) << endl;
    00436       it = languageList.remove( it );
    00437     }
    00438   }
    00439   // now this has left the first element of the list unchecked.
    00440   // The question why this is the case is left as an exercise for the reader...
    00441   // Besides the list might have been empty all the way, so check that too.
    00442   if ( languageList.begin() != languageList.end() ) {
    00443      QStringList::Iterator it = languageList.begin(); // now pointing to the first element
    00444      // kdDebug() << "checking " << (*it) << endl;
    00445      if( (*it).isEmpty() || !(isApplicationTranslatedInto( *it )) ) {
    00446         // kdDebug() << "removing " << (*it) << endl;
    00447         languageList.remove( it ); // that's what the iterator was for...
    00448      }
    00449   }
    00450
    00451   if ( languageList.isEmpty() ) {
    00452     // user picked no language, so we assume he/she speaks English.
    00453     languageList.append( defaultLanguage() );
    00454   }
    00455   m_language = languageList.first(); // keep this for shortcut evaluations
    00456
    00457   d->languageList = languageList; // keep this new list of languages to use
    00458   d->langTwoAlpha.clear(); // Flush cache
    00459
    00460   // important when called from the outside and harmless when called before populating the
    00461   // catalog name list
    00462   updateCatalogues();
    00463
    00464   return true; // we found something. Maybe it's only English, but we found something
    00465 }
    00466
    00467 bool KLocale::isApplicationTranslatedInto( const QString & language)
    00468 {
    00469   if ( language.isEmpty() ) {
    00470     return false;
    00471   }
    00472
    00473   if ( language == defaultLanguage() ) {
    00474     // en_us is always "installed"
    00475     return true;
    00476   }
    00477
    00478   QString appName = d->appName;
    00479   if (maincatalogue) {
    00480     appName = QString::fromLatin1(maincatalogue);
    00481   }
    00482   // sorry, catalogueFileName requires catalog object,k which we do not have here
    00483   // path finding was supposed to be moved completely to KCatalogue. The interface cannot
    00484   // be changed that far during deep freeze. So in order to fix the bug now, we have
    00485   // duplicated code for file path evaluation. Cleanup will follow later. We could have e.g.
    00486   // a static method in KCataloge that can translate between these file names.
    00487   // a stat
    00488   QString sFileName = QString::fromLatin1("%1/LC_MESSAGES/%2.mo")
    00489     .arg( language )
    00490     .arg( appName );
    00491   // kdDebug() << "isApplicationTranslatedInto: filename " << sFileName << endl;
    00492
    00493   QString sAbsFileName = locate( "locale", sFileName );
    00494   // kdDebug() << "isApplicationTranslatedInto: absname " << sAbsFileName << endl;
    00495   return ! sAbsFileName.isEmpty();
    00496 }
    00497
    00498 void KLocale::splitLocale(const QString & aStr,
    00499               QString & language,
    00500               QString & country,
    00501               QString & chrset)
    00502 {
    00503   QString str = aStr;
    00504
    00505   // just in case, there is another language appended
    00506   int f = str.find(':');
    00507   if (f >= 0)
    00508     str.truncate(f);
    00509
    00510   country = QString::null;
    00511   chrset = QString::null;
    00512   language = QString::null;
    00513
    00514   f = str.find('.');
    00515   if (f >= 0)
    00516     {
    00517       chrset = str.mid(f + 1);
    00518       str.truncate(f);
    00519     }
    00520
    00521   f = str.find('_');
    00522   if (f >= 0)
    00523     {
    00524       country = str.mid(f + 1);
    00525       str.truncate(f);
    00526     }
    00527
    00528   language = str;
    00529 }
    00530
    00531 QString KLocale::language() const
    00532 {
    00533   return m_language;
    00534 }
    00535
    00536 QString KLocale::country() const
    00537 {
    00538   return m_country;
    00539 }
    00540
    00541 QString KLocale::monthName(int i, bool shortName) const
    00542 {
    00543   if ( shortName )
    00544     switch ( i )
    00545       {
    00546       case 1:   return translate("January", "Jan");
    00547       case 2:   return translate("February", "Feb");
    00548       case 3:   return translate("March", "Mar");
    00549       case 4:   return translate("April", "Apr");
    00550       case 5:   return translate("May short", "May");
    00551       case 6:   return translate("June", "Jun");
    00552       case 7:   return translate("July", "Jul");
    00553       case 8:   return translate("August", "Aug");
    00554       case 9:   return translate("September", "Sep");
    00555       case 10:  return translate("October", "Oct");
    00556       case 11:  return translate("November", "Nov");
    00557       case 12:  return translate("December", "Dec");
    00558       }
    00559   else
    00560     switch (i)
    00561       {
    00562       case 1:   return translate("January");
    00563       case 2:   return translate("February");
    00564       case 3:   return translate("March");
    00565       case 4:   return translate("April");
    00566       case 5:   return translate("May long", "May");
    00567       case 6:   return translate("June");
    00568       case 7:   return translate("July");
    00569       case 8:   return translate("August");
    00570       case 9:   return translate("September");
    00571       case 10:  return translate("October");
    00572       case 11:  return translate("November");
    00573       case 12:  return translate("December");
    00574       }
    00575
    00576   return QString::null;
    00577 }
    00578
    00579 QString KLocale::monthNamePossessive(int i, bool shortName) const
    00580 {
    00581   if ( shortName )
    00582     switch ( i )
    00583       {
    00584       case 1:   return translate("of January", "of Jan");
    00585       case 2:   return translate("of February", "of Feb");
    00586       case 3:   return translate("of March", "of Mar");
    00587       case 4:   return translate("of April", "of Apr");
    00588       case 5:   return translate("of May short", "of May");
    00589       case 6:   return translate("of June", "of Jun");
    00590       case 7:   return translate("of July", "of Jul");
    00591       case 8:   return translate("of August", "of Aug");
    00592       case 9:   return translate("of September", "of Sep");
    00593       case 10:  return translate("of October", "of Oct");
    00594       case 11:  return translate("of November", "of Nov");
    00595       case 12:  return translate("of December", "of Dec");
    00596       }
    00597   else
    00598     switch (i)
    00599       {
    00600       case 1:   return translate("of January");
    00601       case 2:   return translate("of February");
    00602       case 3:   return translate("of March");
    00603       case 4:   return translate("of April");
    00604       case 5:   return translate("of May long", "of May");
    00605       case 6:   return translate("of June");
    00606       case 7:   return translate("of July");
    00607       case 8:   return translate("of August");
    00608       case 9:   return translate("of September");
    00609       case 10:  return translate("of October");
    00610       case 11:  return translate("of November");
    00611       case 12:  return translate("of December");
    00612       }
    00613
    00614   return QString::null;
    00615 }
    00616
    00617 QString KLocale::weekDayName (int i, bool shortName) const
    00618 {
    00619   return calendar()->weekDayName(i, shortName);
    00620 }
    00621
    00622 void KLocale::insertCatalogue( const QString & catalog )
    00623 {
    00624   if ( !d->catalogNames.contains( catalog) ) {
    00625     d->catalogNames.append( catalog );
    00626   }
    00627   updateCatalogues( ); // evaluate the changed list and generate the neccessary KCatalog objects
    00628 }
    00629
    00630 void KLocale::updateCatalogues( )
    00631 {
    00632   // some changes have occured. Maybe we have learned or forgotten some languages.
    00633   // Maybe the language precedence has changed.
    00634   // Maybe we have learned or forgotten some catalog names.
    00635   // Now examine the list of KCatalogue objects and change it according to the new circumstances.
    00636
    00637   // this could be optimized: try to reuse old KCatalog objects, but remember that the order of
    00638   // catalogs might have changed: e.g. in this fashion
    00639   // 1) move all catalogs into a temporary list
    00640   // 2) iterate over all languages and catalog names
    00641   // 3.1) pick the catalog from the saved list, if it already exists
    00642   // 3.2) else create a new catalog.
    00643   // but we will do this later.
    00644
    00645   for ( QValueList<KCatalogue>::Iterator it = d->catalogues.begin();
    00646     it != d->catalogues.end(); )
    00647   {
    00648      it = d->catalogues.remove(it);
    00649   }
    00650
    00651   // now iterate over all languages and all wanted catalog names and append or create them in the right order
    00652   // the sequence must be e.g. nds/appname nds/kdelibs nds/kio de/appname de/kdelibs de/kio etc.
    00653   // and not nds/appname de/appname nds/kdelibs de/kdelibs etc. Otherwise we would be in trouble with a language
    00654   // sequende nds,en_US, de. In this case en_US must hide everything below in the language list.
    00655   for ( QStringList::ConstIterator itLangs =  d->languageList.begin();
    00656       itLangs != d->languageList.end(); ++itLangs)
    00657   {
    00658     for ( QStringList::ConstIterator itNames =  d->catalogNames.begin();
    00659     itNames != d->catalogNames.end(); ++itNames)
    00660     {
    00661       KCatalogue cat( *itNames, *itLangs ); // create Catalog for this name and this language
    00662       d->catalogues.append( cat );
    00663     }
    00664   }
    00665   initPluralTypes();  // evaluate the plural type for all languages and remember this in each KCatalogue
    00666 }
    00667
    00668
    00669
    00670
    00671 void KLocale::removeCatalogue(const QString &catalog)
    00672 {
    00673   if ( d->catalogNames.contains( catalog )) {
    00674     d->catalogNames.remove( catalog );
    00675     if (KGlobal::_instance)
    00676       updateCatalogues();  // walk through the KCatalogue instances and weed out everything we no longer need
    00677   }
    00678 }
    00679
    00680 void KLocale::setActiveCatalogue(const QString &catalog)
    00681 {
    00682   if ( d->catalogNames.contains( catalog ) ) {
    00683     d->catalogNames.remove( catalog );
    00684     d->catalogNames.prepend( catalog );
    00685     updateCatalogues();  // walk through the KCatalogue instances and adapt to the new order
    00686   }
    00687 }
    00688
    00689 KLocale::~KLocale()
    00690 {
    00691   delete d->calendar;
    00692   delete d->languages;
    00693   delete d;
    00694   d = 0L;
    00695 }
    00696
    00697 QString KLocale::translate_priv(const char *msgid,
    00698                 const char *fallback,
    00699                 const char **translated,
    00700                 int* pluralType ) const
    00701 {
    00702   if ( pluralType) {
    00703     *pluralType = -1; // unless we find something more precise
    00704   }
    00705   if (!msgid || !msgid[0])
    00706     {
    00707       kdWarning() << "KLocale: trying to look up \"\" in catalog. "
    00708            << "Fix the program" << endl;
    00709       return QString::null;
    00710     }
    00711
    00712   if ( useDefaultLanguage() ) { // shortcut evaluation if en_US is main language: do not consult the catalogs
    00713     return QString::fromUtf8( fallback );
    00714   }
    00715
    00716   for ( QValueList<KCatalogue>::ConstIterator it = d->catalogues.begin();
    00717     it != d->catalogues.end();
    00718     ++it )
    00719     {
    00720       // shortcut evaluation: once we have arrived at en_US (default language) we cannot consult
    00721       // the catalog as it will not have an assiciated mo-file. For this default language we can
    00722       // immediately pick the fallback string.
    00723       if ( (*it).language() == defaultLanguage() ) {
    00724         return QString::fromUtf8( fallback );
    00725       }
    00726
    00727       const char * text = (*it).translate( msgid );
    00728
    00729       if ( text )
    00730     {
    00731       // we found it
    00732       if (translated) {
    00733         *translated = text;
    00734       }
    00735       if ( pluralType) {
    00736         *pluralType = (*it).pluralType(); // remember the plural type information from the catalog that was used
    00737       }
    00738       return QString::fromUtf8( text );
    00739     }
    00740     }
    00741
    00742   // Always use UTF-8 if the string was not found
    00743   return QString::fromUtf8( fallback );
    00744 }
    00745
    00746 QString KLocale::translate(const char* msgid) const
    00747 {
    00748   return translate_priv(msgid, msgid);
    00749 }
    00750
    00751 QString KLocale::translate( const char *index, const char *fallback) const
    00752 {
    00753   if (!index || !index[0] || !fallback || !fallback[0])
    00754     {
    00755       kdDebug(173) << "KLocale: trying to look up \"\" in catalog. "
    00756            << "Fix the program" << endl;
    00757       return QString::null;
    00758     }
    00759
    00760   if ( useDefaultLanguage() )
    00761     return QString::fromUtf8( fallback );
    00762
    00763   char *newstring = new char[strlen(index) + strlen(fallback) + 5];
    00764   sprintf(newstring, "_: %s\n%s", index, fallback);
    00765   // as copying QString is very fast, it looks slower as it is ;/
    00766   QString r = translate_priv(newstring, fallback);
    00767   delete [] newstring;
    00768
    00769   return r;
    00770 }
    00771
    00772 static QString put_n_in(const QString &orig, unsigned long n)
    00773 {
    00774   QString ret = orig;
    00775   int index = ret.find("%n");
    00776   if (index == -1)
    00777     return ret;
    00778   ret.replace(index, 2, QString::number(n));
    00779   return ret;
    00780 }
    00781
    00782 #define EXPECT_LENGTH(x) \
    00783    if (forms.count() != x) { \
    00784       kdError() << "translation of \"" << singular << "\" doesn't contain " << x << " different plural forms as expected\n"; \
    00785       return QString( "BROKEN TRANSLATION %1" ).arg( singular ); }
    00786
    00787 QString KLocale::translate( const char *singular, const char *plural,
    00788                             unsigned long n ) const
    00789 {
    00790   if (!singular || !singular[0] || !plural || !plural[0])
    00791     {
    00792       kdWarning() << "KLocale: trying to look up \"\" in catalog. "
    00793            << "Fix the program" << endl;
    00794       return QString::null;
    00795     }
    00796
    00797   char *newstring = new char[strlen(singular) + strlen(plural) + 6];
    00798   sprintf(newstring, "_n: %s\n%s", singular, plural);
    00799   // as copying QString is very fast, it looks slower as it is ;/
    00800   int pluralType = -1;
    00801   QString r = translate_priv(newstring, 0, 0, &pluralType);
    00802   delete [] newstring;
    00803
    00804   if ( r.isEmpty() || useDefaultLanguage() || pluralType == -1) {
    00805     if ( n == 1 ) {
    00806       return put_n_in( QString::fromUtf8( singular ),  n );
    00807     } else {
    00808       QString tmp = QString::fromUtf8( plural );
    00809 #ifndef NDEBUG
    00810       if (tmp.find("%n") == -1) {
    00811               kdDebug() << "the message for i18n should contain a '%n'! " << plural << endl;
    00812       }
    00813 #endif
    00814       return put_n_in( tmp,  n );
    00815     }
    00816   }
    00817
    00818   QStringList forms = QStringList::split( "\n", r, false );
    00819   switch ( pluralType ) {
    00820   case 0: // NoPlural
    00821     EXPECT_LENGTH( 1 );
    00822     return put_n_in( forms[0], n);
    00823   case 1: // TwoForms
    00824     EXPECT_LENGTH( 2 );
    00825     if ( n == 1 )
    00826       return put_n_in( forms[0], n);
    00827     else
    00828       return put_n_in( forms[1], n);
    00829   case 2: // French
    00830     EXPECT_LENGTH( 2 );
    00831     if ( n == 1 || n == 0 )
    00832       return put_n_in( forms[0], n);
    00833     else
    00834       return put_n_in( forms[1], n);
    00835   case 3: // OneTwoRest
    00836     EXPECT_LENGTH( 3 );
    00837     if ( n == 1 )
    00838       return put_n_in( forms[0], n);
    00839     else if ( n == 2 )
    00840       return put_n_in( forms[1], n);
    00841     else
    00842       return put_n_in( forms[2], n);
    00843   case 4: // Russian, corrected by mok
    00844     EXPECT_LENGTH( 3 );
    00845     if ( n%10 == 1  &&  n%100 != 11)
    00846       return put_n_in( forms[0], n); // odin fail
    00847     else if (( n%10 >= 2 && n%10 <=4 ) && (n%100<10 || n%100>20))
    00848       return put_n_in( forms[1], n); // dva faila
    00849     else
    00850       return put_n_in( forms[2], n); // desyat' failov
    00851   case 5: // Polish
    00852     EXPECT_LENGTH( 3 );
    00853     if ( n == 1 )
    00854       return put_n_in( forms[0], n);
    00855     else if ( n%10 >= 2 && n%10 <=4 && (n%100<10 || n%100>=20) )
    00856       return put_n_in( forms[1], n);
    00857     else
    00858       return put_n_in( forms[2], n);
    00859   case 6: // Slovenian
    00860     EXPECT_LENGTH( 4 );
    00861     if ( n%100 == 1 )
    00862       return put_n_in( forms[1], n); // ena datoteka
    00863     else if ( n%100 == 2 )
    00864       return put_n_in( forms[2], n); // dve datoteki
    00865     else if ( n%100 == 3 || n%100 == 4 )
    00866       return put_n_in( forms[3], n); // tri datoteke
    00867     else
    00868       return put_n_in( forms[0], n); // sto datotek
    00869   case 7: // Lithuanian
    00870     EXPECT_LENGTH( 3 );
    00871     if ( n%10 == 0 || (n%100>=11 && n%100<=19) )
    00872       return put_n_in( forms[2], n);
    00873     else if ( n%10 == 1 )
    00874       return put_n_in( forms[0], n);
    00875     else
    00876       return put_n_in( forms[1], n);
    00877   case 8: // Czech
    00878     EXPECT_LENGTH( 3 );
    00879     if ( n%100 == 1 )
    00880       return put_n_in( forms[0], n);
    00881     else if (( n%100 >= 2 ) && ( n%100 <= 4 ))
    00882       return put_n_in( forms[1], n);
    00883     else
    00884       return put_n_in( forms[2], n);
    00885   case 9: // Slovak
    00886     EXPECT_LENGTH( 3 );
    00887     if ( n == 1 )
    00888       return put_n_in( forms[0], n);
    00889     else if (( n >= 2 ) && ( n <= 4 ))
    00890       return put_n_in( forms[1], n);
    00891     else
    00892       return put_n_in( forms[2], n);
    00893   case 10: // Maltese
    00894     EXPECT_LENGTH( 4 );
    00895     if ( n == 1 )
    00896       return put_n_in( forms[0], n );
    00897     else if ( ( n == 0 ) || ( n%100 > 0 && n%100 <= 10 ) )
    00898       return put_n_in( forms[1], n );
    00899     else if ( n%100 > 10 && n%100 < 20 )
    00900       return put_n_in( forms[2], n );
    00901     else
    00902       return put_n_in( forms[3], n );
    00903   case 11: // Arabic
    00904     EXPECT_LENGTH( 4 );
    00905     if (n == 1)
    00906       return put_n_in(forms[0], n);
    00907     else if (n == 2)
    00908       return put_n_in(forms[1], n);
    00909     else if ( n < 11)
    00910       return put_n_in(forms[2], n);
    00911     else
    00912       return put_n_in(forms[3], n);
    00913   case 12: // Balcan
    00914      EXPECT_LENGTH( 3 );
    00915      if (n != 11 && n % 10 == 1)
    00916     return put_n_in(forms[0], n);
    00917      else if (n / 10 != 1 && n % 10 >= 2 && n % 10 <= 4)
    00918     return put_n_in(forms[1], n);
    00919      else
    00920     return put_n_in(forms[2], n);
    00921   case 13: // Macedonian
    00922      EXPECT_LENGTH(3);
    00923      if (n % 10 == 1)
    00924     return put_n_in(forms[0], n);
    00925      else if (n % 10 == 2)
    00926     return put_n_in(forms[1], n);
    00927      else
    00928     return put_n_in(forms[2], n);
    00929   case 14: // Gaeilge
    00930       EXPECT_LENGTH(5);
    00931       if (n == 1)                       // "ceann amhain"
    00932           return put_n_in(forms[0], n);
    00933       else if (n == 2)                  // "dha cheann"
    00934           return put_n_in(forms[1], n);
    00935       else if (n < 7)                   // "%n cinn"
    00936           return put_n_in(forms[2], n);
    00937       else if (n < 11)                  // "%n gcinn"
    00938           return put_n_in(forms[3], n);
    00939       else                              // "%n ceann"
    00940           return put_n_in(forms[4], n);
    00941   }
    00942   kdFatal() << "The function should have been returned in another way\n";
    00943
    00944   return QString::null;
    00945 }
    00946
    00947 QString KLocale::translateQt( const char *context, const char *source,
    00948                   const char *message) const
    00949 {
    00950   if (!source || !source[0]) {
    00951     kdWarning() << "KLocale: trying to look up \"\" in catalog. "
    00952         << "Fix the program" << endl;
    00953     return QString::null;
    00954   }
    00955
    00956   if ( useDefaultLanguage() ) {
    00957     return QString::null;
    00958   }
    00959
    00960   char *newstring = 0;
    00961   const char *translation = 0;
    00962   QString r;
    00963
    00964   if ( message && message[0]) {
    00965     char *newstring = new char[strlen(source) + strlen(message) + 5];
    00966     sprintf(newstring, "_: %s\n%s", source, message);
    00967     const char *translation = 0;
    00968     // as copying QString is very fast, it looks slower as it is ;/
    00969     r = translate_priv(newstring, source, &translation);
    00970     delete [] newstring;
    00971     if (translation)
    00972       return r;
    00973   }
    00974
    00975   if ( context && context[0] && message && message[0]) {
    00976     newstring = new char[strlen(context) + strlen(message) + 5];
    00977     sprintf(newstring, "_: %s\n%s", context, message);
    00978     // as copying QString is very fast, it looks slower as it is ;/
    00979     r = translate_priv(newstring, source, &translation);
    00980     delete [] newstring;
    00981     if (translation)
    00982       return r;
    00983   }
    00984
    00985   r = translate_priv(source, source, &translation);
    00986   if (translation)
    00987     return r;
    00988   return QString::null;
    00989 }
    00990
    00991 bool KLocale::nounDeclension() const
    00992 {
    00993   doFormatInit();
    00994   return d->nounDeclension;
    00995 }
    00996
    00997 bool KLocale::dateMonthNamePossessive() const
    00998 {
    00999   doFormatInit();
    01000   return d->dateMonthNamePossessive;
    01001 }
    01002
    01003 int KLocale::weekStartDay() const
    01004 {
    01005   doFormatInit();
    01006   return d->weekStartDay;
    01007 }
    01008
    01009 bool KLocale::weekStartsMonday() const //deprecated
    01010 {
    01011   doFormatInit();
    01012   return (d->weekStartDay==1);
    01013 }
    01014
    01015 QString KLocale::decimalSymbol() const
    01016 {
    01017   doFormatInit();
    01018   return m_decimalSymbol;
    01019 }
    01020
    01021 QString KLocale::thousandsSeparator() const
    01022 {
    01023   doFormatInit();
    01024   return m_thousandsSeparator;
    01025 }
    01026
    01027 QString KLocale::currencySymbol() const
    01028 {
    01029   doFormatInit();
    01030   return m_currencySymbol;
    01031 }
    01032
    01033 QString KLocale::monetaryDecimalSymbol() const
    01034 {
    01035   doFormatInit();
    01036   return m_monetaryDecimalSymbol;
    01037 }
    01038
    01039 QString KLocale::monetaryThousandsSeparator() const
    01040 {
    01041   doFormatInit();
    01042   return m_monetaryThousandsSeparator;
    01043 }
    01044
    01045 QString KLocale::positiveSign() const
    01046 {
    01047   doFormatInit();
    01048   return m_positiveSign;
    01049 }
    01050
    01051 QString KLocale::negativeSign() const
    01052 {
    01053   doFormatInit();
    01054   return m_negativeSign;
    01055 }
    01056
    01057 int KLocale::fracDigits() const
    01058 {
    01059   doFormatInit();
    01060   return m_fracDigits;
    01061 }
    01062
    01063 bool KLocale::positivePrefixCurrencySymbol() const
    01064 {
    01065   doFormatInit();
    01066   return m_positivePrefixCurrencySymbol;
    01067 }
    01068
    01069 bool KLocale::negativePrefixCurrencySymbol() const
    01070 {
    01071   doFormatInit();
    01072   return m_negativePrefixCurrencySymbol;
    01073 }
    01074
    01075 KLocale::SignPosition KLocale::positiveMonetarySignPosition() const
    01076 {
    01077   doFormatInit();
    01078   return m_positiveMonetarySignPosition;
    01079 }
    01080
    01081 KLocale::SignPosition KLocale::negativeMonetarySignPosition() const
    01082 {
    01083   doFormatInit();
    01084   return m_negativeMonetarySignPosition;
    01085 }
    01086
    01087 static inline void put_it_in( QChar *buffer, uint& index, const QString &s )
    01088 {
    01089   for ( uint l = 0; l < s.length(); l++ )
    01090     buffer[index++] = s.at( l );
    01091 }
    01092
    01093 static inline void put_it_in( QChar *buffer, uint& index, int number )
    01094 {
    01095   buffer[index++] = number / 10 + '0';
    01096   buffer[index++] = number % 10 + '0';
    01097 }
    01098
    01099 QString KLocale::formatMoney(double num,
    01100                  const QString & symbol,
    01101                  int precision) const
    01102 {
    01103   // some defaults
    01104   QString currency = symbol.isNull()
    01105     ? currencySymbol()
    01106     : symbol;
    01107   if (precision < 0) precision = fracDigits();
    01108
    01109   // the number itself
    01110   bool neg = num < 0;
    01111   QString res = QString::number(neg?-num:num, 'f', precision);
    01112   int pos = res.find('.');
    01113   if (pos == -1) pos = res.length();
    01114   else res.replace(pos, 1, monetaryDecimalSymbol());
    01115
    01116   while (0 < (pos -= 3))
    01117     res.insert(pos, monetaryThousandsSeparator()); // thousend sep
    01118
    01119   // set some variables we need later
    01120   int signpos = neg
    01121     ? negativeMonetarySignPosition()
    01122     : positiveMonetarySignPosition();
    01123   QString sign = neg
    01124     ? negativeSign()
    01125     : positiveSign();
    01126
    01127   switch (signpos)
    01128     {
    01129     case ParensAround:
    01130       res.prepend('(');
    01131       res.append (')');
    01132       break;
    01133     case BeforeQuantityMoney:
    01134       res.prepend(sign);
    01135       break;
    01136     case AfterQuantityMoney:
    01137       res.append(sign);
    01138       break;
    01139     case BeforeMoney:
    01140       currency.prepend(sign);
    01141       break;
    01142     case AfterMoney:
    01143       currency.append(sign);
    01144       break;
    01145     }
    01146
    01147   if (neg?negativePrefixCurrencySymbol():
    01148       positivePrefixCurrencySymbol())
    01149     {
    01150       res.prepend(' ');
    01151       res.prepend(currency);
    01152     } else {
    01153       res.append (' ');
    01154       res.append (currency);
    01155     }
    01156
    01157   return res;
    01158 }
    01159
    01160 QString KLocale::formatMoney(const QString &numStr) const
    01161 {
    01162   return formatMoney(numStr.toDouble());
    01163 }
    01164
    01165 QString KLocale::formatNumber(double num, int precision) const
    01166 {
    01167   bool neg = num < 0;
    01168   if (precision == -1) precision = 2;
    01169   QString res = QString::number(neg?-num:num, 'f', precision);
    01170   int pos = res.find('.');
    01171   if (pos == -1) pos = res.length();
    01172   else res.replace(pos, 1, decimalSymbol());
    01173
    01174   while (0 < (pos -= 3))
    01175     res.insert(pos, thousandsSeparator()); // thousand sep
    01176
    01177   // How can we know where we should put the sign?
    01178   res.prepend(neg?negativeSign():positiveSign());
    01179
    01180   return res;
    01181 }
    01182
    01183 QString KLocale::formatLong(long num) const
    01184 {
    01185   return formatNumber((double)num, 0);
    01186 }
    01187
    01188 QString KLocale::formatNumber(const QString &numStr) const
    01189 {
    01190   return formatNumber(numStr.toDouble());
    01191 }
    01192
    01193 QString KLocale::formatDate(const QDate &pDate, bool shortFormat) const
    01194 {
    01195   const QString rst = shortFormat?dateFormatShort():dateFormat();
    01196
    01197   QString buffer;
    01198
    01199   if ( ! pDate.isValid() ) return buffer;
    01200
    01201   bool escape = false;
    01202
    01203   int year = calendar()->year(pDate);
    01204   int month = calendar()->month(pDate);
    01205
    01206   for ( uint format_index = 0; format_index < rst.length(); ++format_index )
    01207     {
    01208       if ( !escape )
    01209     {
    01210       if ( rst.at( format_index ).unicode() == '%' )
    01211         escape = true;
    01212       else
    01213         buffer.append(rst.at(format_index));
    01214     }
    01215       else
    01216     {
    01217       switch ( rst.at( format_index ).unicode() )
    01218         {
    01219         case '%':
    01220           buffer.append('%');
    01221           break;
    01222         case 'Y':
    01223           buffer.append(calendar()->yearString(pDate, false));
    01224           break;
    01225         case 'y':
    01226           buffer.append(calendar()->yearString(pDate, true));
    01227           break;
    01228         case 'n':
    01229               buffer.append(calendar()->monthString(pDate, true));
    01230           break;
    01231         case 'e':
    01232               buffer.append(calendar()->dayString(pDate, true));
    01233           break;
    01234         case 'm':
    01235               buffer.append(calendar()->monthString(pDate, false));
    01236           break;
    01237         case 'b':
    01238           if (d->nounDeclension && d->dateMonthNamePossessive)
    01239         buffer.append(calendar()->monthNamePossessive(month, year, true));
    01240           else
    01241         buffer.append(calendar()->monthName(month, year, true));
    01242           break;
    01243         case 'B':
    01244           if (d->nounDeclension && d->dateMonthNamePossessive)
    01245         buffer.append(calendar()->monthNamePossessive(month, year, false));
    01246           else
    01247         buffer.append(calendar()->monthName(month, year, false));
    01248           break;
    01249         case 'd':
    01250               buffer.append(calendar()->dayString(pDate, false));
    01251           break;
    01252         case 'a':
    01253           buffer.append(calendar()->weekDayName(pDate, true));
    01254           break;
    01255         case 'A':
    01256           buffer.append(calendar()->weekDayName(pDate, false));
    01257           break;
    01258         default:
    01259           buffer.append(rst.at(format_index));
    01260           break;
    01261         }
    01262       escape = false;
    01263     }
    01264     }
    01265   return buffer;
    01266 }
    01267
    01268 void KLocale::setMainCatalogue(const char *catalog)
    01269 {
    01270   maincatalogue = catalog;
    01271 }
    01272
    01273 double KLocale::readNumber(const QString &_str, bool * ok) const
    01274 {
    01275   QString str = _str.stripWhiteSpace();
    01276   bool neg = str.find(negativeSign()) == 0;
    01277   if (neg)
    01278     str.remove( 0, negativeSign().length() );
    01279
    01280   /* will hold the scientific notation portion of the number.
    01281      Example, with 2.34E+23, exponentialPart == "E+23"
    01282   */
    01283   QString exponentialPart;
    01284   int EPos;
    01285
    01286   EPos = str.find('E', 0, false);
    01287
    01288   if (EPos != -1)
    01289   {
    01290     exponentialPart = str.mid(EPos);
    01291     str = str.left(EPos);
    01292   }
    01293
    01294   int pos = str.find(decimalSymbol());
    01295   QString major;
    01296   QString minor;
    01297   if ( pos == -1 )
    01298     major = str;
    01299   else
    01300     {
    01301       major = str.left(pos);
    01302       minor = str.mid(pos + decimalSymbol().length());
    01303     }
    01304
    01305   // Remove thousand separators
    01306   int thlen = thousandsSeparator().length();
    01307   int lastpos = 0;
    01308   while ( ( pos = major.find( thousandsSeparator() ) ) > 0 )
    01309   {
    01310     // e.g. 12,,345,,678,,922 Acceptable positions (from the end) are 5, 10, 15... i.e. (3+thlen)*N
    01311     int fromEnd = major.length() - pos;
    01312     if ( fromEnd % (3+thlen) != 0 // Needs to be a multiple, otherwise it's an error
    01313         || pos - lastpos > 3 // More than 3 digits between two separators -> error
    01314         || pos == 0          // Can't start with a separator
    01315         || (lastpos>0 && pos-lastpos!=3))   // Must have exactly 3 digits between two separators
    01316     {
    01317       if (ok) *ok = false;
    01318       return 0.0;
    01319     }
    01320
    01321     lastpos = pos;
    01322     major.remove( pos, thlen );
    01323   }
    01324   if (lastpos>0 && major.length()-lastpos!=3)   // Must have exactly 3 digits after the last separator
    01325   {
    01326     if (ok) *ok = false;
    01327     return 0.0;
    01328   }
    01329
    01330   QString tot;
    01331   if (neg) tot = '-';
    01332
    01333   tot += major + '.' + minor + exponentialPart;
    01334
    01335   return tot.toDouble(ok);
    01336 }
    01337
    01338 double KLocale::readMoney(const QString &_str, bool * ok) const
    01339 {
    01340   QString str = _str.stripWhiteSpace();
    01341   bool neg = false;
    01342   bool currencyFound = false;
    01343   // First try removing currency symbol from either end
    01344   int pos = str.find(currencySymbol());
    01345   if ( pos == 0 || pos == (int) str.length()-1 )
    01346     {
    01347       str.remove(pos,currencySymbol().length());
    01348       str = str.stripWhiteSpace();
    01349       currencyFound = true;
    01350     }
    01351   if (str.isEmpty())
    01352     {
    01353       if (ok) *ok = false;
    01354       return 0;
    01355     }
    01356   // Then try removing negative sign from either end
    01357   // (with a special case for parenthesis)
    01358   if (negativeMonetarySignPosition() == ParensAround)
    01359     {
    01360       if (str[0] == '(' && str[str.length()-1] == ')')
    01361         {
    01362       neg = true;
    01363       str.remove(str.length()-1,1);
    01364       str.remove(0,1);
    01365         }
    01366     }
    01367   else
    01368     {
    01369       int i1 = str.find(negativeSign());
    01370       if ( i1 == 0 || i1 == (int) str.length()-1 )
    01371         {
    01372       neg = true;
    01373       str.remove(i1,negativeSign().length());
    01374         }
    01375     }
    01376   if (neg) str = str.stripWhiteSpace();
    01377
    01378   // Finally try again for the currency symbol, if we didn't find
    01379   // it already (because of the negative sign being in the way).
    01380   if ( !currencyFound )
    01381     {
    01382       pos = str.find(currencySymbol());
    01383       if ( pos == 0 || pos == (int) str.length()-1 )
    01384         {
    01385       str.remove(pos,currencySymbol().length());
    01386       str = str.stripWhiteSpace();
    01387         }
    01388     }
    01389
    01390   // And parse the rest as a number
    01391   pos = str.find(monetaryDecimalSymbol());
    01392   QString major;
    01393   QString minior;
    01394   if (pos == -1)
    01395     major = str;
    01396   else
    01397     {
    01398       major = str.left(pos);
    01399       minior = str.mid(pos + monetaryDecimalSymbol().length());
    01400     }
    01401
    01402   // Remove thousand separators
    01403   int thlen = monetaryThousandsSeparator().length();
    01404   int lastpos = 0;
    01405   while ( ( pos = major.find( monetaryThousandsSeparator() ) ) > 0 )
    01406   {
    01407     // e.g. 12,,345,,678,,922 Acceptable positions (from the end) are 5, 10, 15... i.e. (3+thlen)*N
    01408     int fromEnd = major.length() - pos;
    01409     if ( fromEnd % (3+thlen) != 0 // Needs to be a multiple, otherwise it's an error
    01410         || pos - lastpos > 3 // More than 3 digits between two separators -> error
    01411         || pos == 0          // Can't start with a separator
    01412         || (lastpos>0 && pos-lastpos!=3))   // Must have exactly 3 digits between two separators
    01413     {
    01414       if (ok) *ok = false;
    01415       return 0.0;
    01416     }
    01417     lastpos = pos;
    01418     major.remove( pos, thlen );
    01419   }
    01420   if (lastpos>0 && major.length()-lastpos!=3)   // Must have exactly 3 digits after the last separator
    01421   {
    01422     if (ok) *ok = false;
    01423     return 0.0;
    01424   }
    01425
    01426   QString tot;
    01427   if (neg) tot = '-';
    01428   tot += major + '.' + minior;
    01429   return tot.toDouble(ok);
    01430 }
    01431
    01438 static int readInt(const QString &str, uint &pos)
    01439 {
    01440   if (!str.at(pos).isDigit()) return -1;
    01441   int result = 0;
    01442   for (; str.length() > pos && str.at(pos).isDigit(); pos++)
    01443     {
    01444       result *= 10;
    01445       result += str.at(pos).digitValue();
    01446     }
    01447
    01448   return result;
    01449 }
    01450
    01451 QDate KLocale::readDate(const QString &intstr, bool* ok) const
    01452 {
    01453   QDate date;
    01454   date = readDate(intstr, ShortFormat, ok);
    01455   if (date.isValid()) return date;
    01456   return readDate(intstr, NormalFormat, ok);
    01457 }
    01458
    01459 QDate KLocale::readDate(const QString &intstr, ReadDateFlags flags, bool* ok) const
    01460 {
    01461   QString fmt = ((flags & ShortFormat) ? dateFormatShort() : dateFormat()).simplifyWhiteSpace();
    01462   return readDate( intstr, fmt, ok );
    01463 }
    01464
    01465 QDate KLocale::readDate(const QString &intstr, const QString &fmt, bool* ok) const
    01466 {
    01467   //kdDebug() << "KLocale::readDate intstr=" << intstr << " fmt=" << fmt << endl;
    01468   QString str = intstr.simplifyWhiteSpace().lower();
    01469   int day = -1, month = -1;
    01470   // allow the year to be omitted if not in the format
    01471   int year = calendar()->year(QDate::currentDate());
    01472   uint strpos = 0;
    01473   uint fmtpos = 0;
    01474
    01475   int iLength; // Temporary variable used when reading input
    01476
    01477   bool error = false;
    01478
    01479   while (fmt.length() > fmtpos && str.length() > strpos && !error)
    01480   {
    01481
    01482     QChar c = fmt.at(fmtpos++);
    01483
    01484     if (c != '%') {
    01485       if (c.isSpace() && str.at(strpos).isSpace())
    01486         strpos++;
    01487       else if (c != str.at(strpos++))
    01488         error = true;
    01489     }
    01490     else
    01491     {
    01492       int j;
    01493       // remove space at the beginning
    01494       if (str.length() > strpos && str.at(strpos).isSpace())
    01495         strpos++;
    01496
    01497       c = fmt.at(fmtpos++);
    01498       switch (c)
    01499       {
    01500     case 'a':
    01501     case 'A':
    01502
    01503           error = true;
    01504       j = 1;
    01505       while (error && (j < 8)) {
    01506         QString s = calendar()->weekDayName(j, c == 'a').lower();
    01507         int len = s.length();
    01508         if (str.mid(strpos, len) == s)
    01509             {
    01510           strpos += len;
    01511               error = false;
    01512             }
    01513         j++;
    01514       }
    01515       break;
    01516     case 'b':
    01517     case 'B':
    01518
    01519           error = true;
    01520       if (d->nounDeclension && d->dateMonthNamePossessive) {
    01521         j = 1;
    01522         while (error && (j < 13)) {
    01523           QString s = calendar()->monthNamePossessive(j, year, c == 'b').lower();
    01524           int len = s.length();
    01525           if (str.mid(strpos, len) == s) {
    01526             month = j;
    01527             strpos += len;
    01528                 error = false;
    01529           }
    01530           j++;
    01531         }
    01532       }
    01533       j = 1;
    01534       while (error && (j < 13)) {
    01535         QString s = calendar()->monthName(j, year, c == 'b').lower();
    01536         int len = s.length();
    01537         if (str.mid(strpos, len) == s) {
    01538           month = j;
    01539           strpos += len;
    01540               error = false;
    01541         }
    01542         j++;
    01543       }
    01544       break;
    01545     case 'd':
    01546     case 'e':
    01547       day = calendar()->dayStringToInteger(str.mid(strpos), iLength);
    01548       strpos += iLength;
    01549
    01550       error = iLength <= 0;
    01551       break;
    01552
    01553     case 'n':
    01554     case 'm':
    01555       month = calendar()->monthStringToInteger(str.mid(strpos), iLength);
    01556       strpos += iLength;
    01557
    01558       error = iLength <= 0;
    01559       break;
    01560
    01561     case 'Y':
    01562     case 'y':
    01563       year = calendar()->yearStringToInteger(str.mid(strpos), iLength);
    01564       strpos += iLength;
    01565
    01566       error = iLength <= 0;
    01567       break;
    01568       }
    01569     }
    01570   }
    01571
    01572   /* for a match, we should reach the end of both strings, not just one of
    01573      them */
    01574   if ( fmt.length() > fmtpos || str.length() > strpos )
    01575   {
    01576     error = true;
    01577   }
    01578
    01579   //kdDebug(173) << "KLocale::readDate day=" << day << " month=" << month << " year=" << year << endl;
    01580   if ( year != -1 && month != -1 && day != -1 && !error)
    01581   {
    01582     if (ok) *ok = true;
    01583
    01584     QDate result;
    01585     calendar()->setYMD(result, year, month, day);
    01586
    01587     return result;
    01588   }
    01589   else
    01590   {
    01591     if (ok) *ok = false;
    01592     return QDate(); // invalid date
    01593   }
    01594 }
    01595
    01596 QTime KLocale::readTime(const QString &intstr, bool *ok) const
    01597 {
    01598   QTime _time;
    01599   _time = readTime(intstr, WithSeconds, ok);
    01600   if (_time.isValid()) return _time;
    01601   return readTime(intstr, WithoutSeconds, ok);
    01602 }
    01603
    01604 QTime KLocale::readTime(const QString &intstr, ReadTimeFlags flags, bool *ok) const
    01605 {
    01606   QString str = intstr.simplifyWhiteSpace().lower();
    01607   QString Format = timeFormat().simplifyWhiteSpace();
    01608   if (flags & WithoutSeconds)
    01609     Format.remove(QRegExp(".%S"));
    01610
    01611   int hour = -1, minute = -1;
    01612   int second = ( (flags & WithoutSeconds) == 0 ) ? -1 : 0; // don't require seconds
    01613   bool g_12h = false;
    01614   bool pm = false;
    01615   uint strpos = 0;
    01616   uint Formatpos = 0;
    01617
    01618   while (Format.length() > Formatpos || str.length() > strpos)
    01619     {
    01620       if ( !(Format.length() > Formatpos && str.length() > strpos) ) goto error;
    01621
    01622       QChar c = Format.at(Formatpos++);
    01623
    01624       if (c != '%')
    01625     {
    01626       if (c.isSpace())
    01627         strpos++;
    01628       else if (c != str.at(strpos++))
    01629         goto error;
    01630       continue;
    01631     }
    01632
    01633       // remove space at the beginning
    01634       if (str.length() > strpos && str.at(strpos).isSpace())
    01635     strpos++;
    01636
    01637       c = Format.at(Formatpos++);
    01638       switch (c)
    01639     {
    01640     case 'p':
    01641       {
    01642         QString s;
    01643         s = translate("pm").lower();
    01644         int len = s.length();
    01645         if (str.mid(strpos, len) == s)
    01646           {
    01647         pm = true;
    01648         strpos += len;
    01649           }
    01650         else
    01651           {
    01652         s = translate("am").lower();
    01653         len = s.length();
    01654         if (str.mid(strpos, len) == s) {
    01655           pm = false;
    01656           strpos += len;
    01657         }
    01658         else
    01659           goto error;
    01660           }
    01661       }
    01662       break;
    01663
    01664     case 'k':
    01665     case 'H':
    01666       g_12h = false;
    01667       hour = readInt(str, strpos);
    01668       if (hour < 0 || hour > 23)
    01669         goto error;
    01670
    01671       break;
    01672
    01673     case 'l':
    01674     case 'I':
    01675       g_12h = true;
    01676       hour = readInt(str, strpos);
    01677       if (hour < 1 || hour > 12)
    01678         goto error;
    01679
    01680       break;
    01681
    01682     case 'M':
    01683       minute = readInt(str, strpos);
    01684       if (minute < 0 || minute > 59)
    01685         goto error;
    01686
    01687       break;
    01688
    01689     case 'S':
    01690       second = readInt(str, strpos);
    01691       if (second < 0 || second > 59)
    01692         goto error;
    01693
    01694       break;
    01695     }
    01696     }
    01697   if (g_12h) {
    01698     hour %= 12;
    01699     if (pm) hour += 12;
    01700   }
    01701
    01702   if (ok) *ok = true;
    01703   return QTime(hour, minute, second);
    01704
    01705  error:
    01706   if (ok) *ok = false;
    01707   // ######## KDE4: remove this
    01708   return QTime(-1, -1, -1); // return invalid date if it didn't work
    01709 }
    01710
    01711 //BIC: merge with below
    01712 QString KLocale::formatTime(const QTime &pTime, bool includeSecs) const
    01713 {
    01714   return formatTime( pTime, includeSecs, false );
    01715 }
    01716
    01717 QString KLocale::formatTime(const QTime &pTime, bool includeSecs, bool isDuration) const
    01718 {
    01719   const QString rst = timeFormat();
    01720
    01721   // only "pm/am" here can grow, the rest shrinks, but
    01722   // I'm rather safe than sorry
    01723   QChar *buffer = new QChar[rst.length() * 3 / 2 + 30];
    01724
    01725   uint index = 0;
    01726   bool escape = false;
    01727   int number = 0;
    01728
    01729   for ( uint format_index = 0; format_index < rst.length(); format_index++ )
    01730     {
    01731       if ( !escape )
    01732     {
    01733       if ( rst.at( format_index ).unicode() == '%' )
    01734         escape = true;
    01735       else
    01736         buffer[index++] = rst.at( format_index );
    01737     }
    01738       else
    01739     {
    01740       switch ( rst.at( format_index ).unicode() )
    01741         {
    01742         case '%':
    01743           buffer[index++] = '%';
    01744           break;
    01745         case 'H':
    01746           put_it_in( buffer, index, pTime.hour() );
    01747           break;
    01748         case 'I':
    01749           if ( isDuration )
    01750               put_it_in( buffer, index, pTime.hour() );
    01751           else
    01752               put_it_in( buffer, index, ( pTime.hour() + 11) % 12 + 1 );
    01753           break;
    01754         case 'M':
    01755           put_it_in( buffer, index, pTime.minute() );
    01756           break;
    01757         case 'S':
    01758           if (includeSecs)
    01759         put_it_in( buffer, index, pTime.second() );
    01760           else if ( index > 0 )
    01761         {
    01762           // we remove the separator sign before the seconds and
    01763           // assume that works everywhere
    01764           --index;
    01765           break;
    01766         }
    01767           break;
    01768         case 'k':
    01769           number = pTime.hour();
    01770         case 'l':
    01771           // to share the code
    01772           if ( rst.at( format_index ).unicode() == 'l' )
    01773         number = isDuration ? pTime.hour() : (pTime.hour() + 11) % 12 + 1;
    01774           if ( number / 10 )
    01775         buffer[index++] = number / 10 + '0';
    01776           buffer[index++] = number % 10 + '0';
    01777           break;
    01778         case 'p':
    01779           if ( !isDuration )
    01780           {
    01781         QString s;
    01782         if ( pTime.hour() >= 12 )
    01783           put_it_in( buffer, index, translate("pm") );
    01784         else
    01785           put_it_in( buffer, index, translate("am") );
    01786           }
    01787           break;
    01788         default:
    01789           buffer[index++] = rst.at( format_index );
    01790           break;
    01791         }
    01792       escape = false;
    01793     }
    01794     }
    01795   QString ret( buffer, index );
    01796   delete [] buffer;
    01797   if ( isDuration ) // eliminate trailing-space due to " %p"
    01798     return ret.stripWhiteSpace();
    01799   else
    01800     return ret;
    01801 }
    01802
    01803 bool KLocale::use12Clock() const
    01804 {
    01805   if ((timeFormat().contains(QString::fromLatin1("%I")) > 0) ||
    01806       (timeFormat().contains(QString::fromLatin1("%l")) > 0))
    01807     return true;
    01808   else
    01809     return false;
    01810 }
    01811
    01812 QString KLocale::languages() const
    01813 {
    01814   return d->languageList.join( QString::fromLatin1(":") );
    01815 }
    01816
    01817 QStringList KLocale::languageList() const
    01818 {
    01819   return d->languageList;
    01820 }
    01821
    01822 QString KLocale::formatDateTime(const QDateTime &pDateTime,
    01823                 bool shortFormat,
    01824                 bool includeSeconds) const
    01825 {
    01826   return translate("concatenation of dates and time", "%1 %2")
    01827     .arg( formatDate( pDateTime.date(), shortFormat ) )
    01828     .arg( formatTime( pDateTime.time(), includeSeconds ) );
    01829 }
    01830
    01831 QString i18n(const char* text)
    01832 {
    01833   register KLocale *instance = KGlobal::locale();
    01834   if (instance)
    01835     return instance->translate(text);
    01836   return QString::fromUtf8(text);
    01837 }
    01838
    01839 QString i18n(const char* index, const char *text)
    01840 {
    01841   register KLocale *instance = KGlobal::locale();
    01842   if (instance)
    01843     return instance->translate(index, text);
    01844   return QString::fromUtf8(text);
    01845 }
    01846
    01847 QString i18n(const char* singular, const char* plural, unsigned long n)
    01848 {
    01849   register KLocale *instance = KGlobal::locale();
    01850   if (instance)
    01851     return instance->translate(singular, plural, n);
    01852   if (n == 1)
    01853     return put_n_in(QString::fromUtf8(singular), n);
    01854   else
    01855     return put_n_in(QString::fromUtf8(plural), n);
    01856 }
    01857
    01858 void KLocale::initInstance()
    01859 {
    01860   if (KGlobal::_locale)
    01861     return;
    01862
    01863   KInstance *app = KGlobal::instance();
    01864   if (app) {
    01865     KGlobal::_locale = new KLocale(QString::fromLatin1(app->instanceName()));
    01866
    01867     // only do this for the global instance
    01868     QTextCodec::setCodecForLocale(KGlobal::_locale->codecForEncoding());
    01869   }
    01870   else
    01871     kdDebug(173) << "no app name available using KLocale - nothing to do\n";
    01872 }
    01873
    01874 QString KLocale::langLookup(const QString &fname, const char *rtype)
    01875 {
    01876   QStringList search;
    01877
    01878   // assemble the local search paths
    01879   const QStringList localDoc = KGlobal::dirs()->resourceDirs(rtype);
    01880
    01881   // look up the different languages
    01882   for (int id=localDoc.count()-1; id >= 0; --id)
    01883     {
    01884       QStringList langs = KGlobal::locale()->languageList();
    01885       langs.append( "en" );
    01886       langs.remove( defaultLanguage() );
    01887       QStringList::ConstIterator lang;
    01888       for (lang = langs.begin(); lang != langs.end(); ++lang)
    01889     search.append(QString("%1%2/%3").arg(localDoc[id]).arg(*lang).arg(fname));
    01890     }
    01891
    01892   // try to locate the file
    01893   QStringList::Iterator it;
    01894   for (it = search.begin(); it != search.end(); ++it)
    01895     {
    01896       kdDebug(173) << "Looking for help in: " << *it << endl;
    01897
    01898       QFileInfo info(*it);
    01899       if (info.exists() && info.isFile() && info.isReadable())
    01900     return *it;
    01901     }
    01902
    01903   return QString::null;
    01904 }
    01905
    01906 bool KLocale::useDefaultLanguage() const
    01907 {
    01908   return language() == defaultLanguage();
    01909 }
    01910
    01911 void KLocale::initEncoding(KConfig *)
    01912 {
    01913   const int mibDefault = 4; // ISO 8859-1
    01914
    01915   // This all made more sense when we still had the EncodingEnum config key.
    01916   setEncoding( QTextCodec::codecForLocale()->mibEnum() );
    01917
    01918   if ( !d->codecForEncoding )
    01919     {
    01920       kdWarning(173) << " Defaulting to ISO 8859-1 encoding." << endl;
    01921       setEncoding(mibDefault);
    01922     }
    01923
    01924   Q_ASSERT( d->codecForEncoding );
    01925 }
    01926
    01927 void KLocale::initFileNameEncoding(KConfig *)
    01928 {
    01929   // If the following environment variable is set, assume all filenames
    01930   // are in UTF-8 regardless of the current C locale.
    01931   d->utf8FileEncoding = getenv("KDE_UTF8_FILENAMES") != 0;
    01932   if (d->utf8FileEncoding)
    01933   {
    01934     QFile::setEncodingFunction(KLocale::encodeFileNameUTF8);
    01935     QFile::setDecodingFunction(KLocale::decodeFileNameUTF8);
    01936   }
    01937   // Otherwise, stay with QFile's default filename encoding functions
    01938   // which, on Unix platforms, use the locale's codec.
    01939 }
    01940
    01941 QCString KLocale::encodeFileNameUTF8( const QString & fileName )
    01942 {
    01943   return fileName.utf8();
    01944 }
    01945
    01946 QString KLocale::decodeFileNameUTF8( const QCString & localFileName )
    01947 {
    01948   return QString::fromUtf8(localFileName);
    01949 }
    01950
    01951 void KLocale::setDateFormat(const QString & format)
    01952 {
    01953   doFormatInit();
    01954   m_dateFormat = format.stripWhiteSpace();
    01955 }
    01956
    01957 void KLocale::setDateFormatShort(const QString & format)
    01958 {
    01959   doFormatInit();
    01960   m_dateFormatShort = format.stripWhiteSpace();
    01961 }
    01962
    01963 void KLocale::setDateMonthNamePossessive(bool possessive)
    01964 {
    01965   doFormatInit();
    01966   d->dateMonthNamePossessive = possessive;
    01967 }
    01968
    01969 void KLocale::setTimeFormat(const QString & format)
    01970 {
    01971   doFormatInit();
    01972   m_timeFormat = format.stripWhiteSpace();
    01973 }
    01974
    01975 void KLocale::setWeekStartsMonday(bool start) //deprecated
    01976 {
    01977   doFormatInit();
    01978   if (start)
    01979     d->weekStartDay = 1;
    01980   else
    01981     d->weekStartDay = 7;
    01982 }
    01983
    01984 void KLocale::setWeekStartDay(int day)
    01985 {
    01986   doFormatInit();
    01987   if (day>7 || day<1)
    01988     d->weekStartDay = 1; //Monday is default
    01989   else
    01990     d->weekStartDay = day;
    01991 }
    01992
    01993 QString KLocale::dateFormat() const
    01994 {
    01995   doFormatInit();
    01996   return m_dateFormat;
    01997 }
    01998
    01999 QString KLocale::dateFormatShort() const
    02000 {
    02001   doFormatInit();
    02002   return m_dateFormatShort;
    02003 }
    02004
    02005 QString KLocale::timeFormat() const
    02006 {
    02007   doFormatInit();
    02008   return m_timeFormat;
    02009 }
    02010
    02011 void KLocale::setDecimalSymbol(const QString & symbol)
    02012 {
    02013   doFormatInit();
    02014   m_decimalSymbol = symbol.stripWhiteSpace();
    02015 }
    02016
    02017 void KLocale::setThousandsSeparator(const QString & separator)
    02018 {
    02019   doFormatInit();
    02020   // allow spaces here
    02021   m_thousandsSeparator = separator;
    02022 }
    02023
    02024 void KLocale::setPositiveSign(const QString & sign)
    02025 {
    02026   doFormatInit();
    02027   m_positiveSign = sign.stripWhiteSpace();
    02028 }
    02029
    02030 void KLocale::setNegativeSign(const QString & sign)
    02031 {
    02032   doFormatInit();
    02033   m_negativeSign = sign.stripWhiteSpace();
    02034 }
    02035
    02036 void KLocale::setPositiveMonetarySignPosition(SignPosition signpos)
    02037 {
    02038   doFormatInit();
    02039   m_positiveMonetarySignPosition = signpos;
    02040 }
    02041
    02042 void KLocale::setNegativeMonetarySignPosition(SignPosition signpos)
    02043 {
    02044   doFormatInit();
    02045   m_negativeMonetarySignPosition = signpos;
    02046 }
    02047
    02048 void KLocale::setPositivePrefixCurrencySymbol(bool prefix)
    02049 {
    02050   doFormatInit();
    02051   m_positivePrefixCurrencySymbol = prefix;
    02052 }
    02053
    02054 void KLocale::setNegativePrefixCurrencySymbol(bool prefix)
    02055 {
    02056   doFormatInit();
    02057   m_negativePrefixCurrencySymbol = prefix;
    02058 }
    02059
    02060 void KLocale::setFracDigits(int digits)
    02061 {
    02062   doFormatInit();
    02063   m_fracDigits = digits;
    02064 }
    02065
    02066 void KLocale::setMonetaryThousandsSeparator(const QString & separator)
    02067 {
    02068   doFormatInit();
    02069   // allow spaces here
    02070   m_monetaryThousandsSeparator = separator;
    02071 }
    02072
    02073 void KLocale::setMonetaryDecimalSymbol(const QString & symbol)
    02074 {
    02075   doFormatInit();
    02076   m_monetaryDecimalSymbol = symbol.stripWhiteSpace();
    02077 }
    02078
    02079 void KLocale::setCurrencySymbol(const QString & symbol)
    02080 {
    02081   doFormatInit();
    02082   m_currencySymbol = symbol.stripWhiteSpace();
    02083 }
    02084
    02085 int KLocale::pageSize() const
    02086 {
    02087   doFormatInit();
    02088   return d->pageSize;
    02089 }
    02090
    02091 void KLocale::setPageSize(int pageSize)
    02092 {
    02093   // #### check if it's in range??
    02094   doFormatInit();
    02095   d->pageSize = pageSize;
    02096 }
    02097
    02098 KLocale::MeasureSystem KLocale::measureSystem() const
    02099 {
    02100   doFormatInit();
    02101   return d->measureSystem;
    02102 }
    02103
    02104 void KLocale::setMeasureSystem(MeasureSystem value)
    02105 {
    02106   doFormatInit();
    02107   d->measureSystem = value;
    02108 }
    02109
    02110 QString KLocale::defaultLanguage()
    02111 {
    02112   return QString::fromLatin1("en_US");
    02113 }
    02114
    02115 QString KLocale::defaultCountry()
    02116 {
    02117   return QString::fromLatin1("C");
    02118 }
    02119
    02120 const char * KLocale::encoding() const
    02121 {
    02122   return codecForEncoding()->name();
    02123 }
    02124
    02125 int KLocale::encodingMib() const
    02126 {
    02127   return codecForEncoding()->mibEnum();
    02128 }
    02129
    02130 int KLocale::fileEncodingMib() const
    02131 {
    02132   if (d->utf8FileEncoding)
    02133      return 106;
    02134   return codecForEncoding()->mibEnum();
    02135 }
    02136
    02137 QTextCodec * KLocale::codecForEncoding() const
    02138 {
    02139   return d->codecForEncoding;
    02140 }
    02141
    02142 bool KLocale::setEncoding(int mibEnum)
    02143 {
    02144   QTextCodec * codec = QTextCodec::codecForMib(mibEnum);
    02145   if (codec)
    02146     d->codecForEncoding = codec;
    02147
    02148   return codec != 0;
    02149 }
    02150
    02151 QStringList KLocale::languagesTwoAlpha() const
    02152 {
    02153   if (d->langTwoAlpha.count())
    02154      return d->langTwoAlpha;
    02155
    02156   const QStringList &origList = languageList();
    02157
    02158   QStringList result;
    02159
    02160   KConfig config(QString::fromLatin1("language.codes"), true, false);
    02161   config.setGroup("TwoLetterCodes");
    02162
    02163   for ( QStringList::ConstIterator it = origList.begin();
    02164     it != origList.end();
    02165     ++it )
    02166     {
    02167       QString lang = *it;
    02168       QStringList langLst;
    02169       if (config.hasKey( lang ))
    02170          langLst = config.readListEntry( lang );
    02171       else
    02172       {
    02173          int i = lang.find('_');
    02174          if (i >= 0)
    02175             lang.truncate(i);
    02176          langLst << lang;
    02177       }
    02178
    02179       for ( QStringList::ConstIterator langIt = langLst.begin();
    02180         langIt != langLst.end();
    02181         ++langIt )
    02182     {
    02183       if ( !(*langIt).isEmpty() && !result.contains( *langIt ) )
    02184         result += *langIt;
    02185     }
    02186     }
    02187   d->langTwoAlpha = result;
    02188   return result;
    02189 }
    02190
    02191 QStringList KLocale::allLanguagesTwoAlpha() const
    02192 {
    02193   if (!d->languages)
    02194     d->languages = new KConfig("all_languages", true, false, "locale");
    02195
    02196   return d->languages->groupList();
    02197 }
    02198
    02199 QString KLocale::twoAlphaToLanguageName(const QString &code) const
    02200 {
    02201   if (!d->languages)
    02202     d->languages = new KConfig("all_languages", true, false, "locale");
    02203
    02204   QString groupName = code;
    02205   const int i = groupName.find('_');
    02206   groupName.replace(0, i, groupName.left(i).lower());
    02207
    02208   d->languages->setGroup(groupName);
    02209   return d->languages->readEntry("Name");
    02210 }
    02211
    02212 QStringList KLocale::allCountriesTwoAlpha() const
    02213 {
    02214   QStringList countries;
    02215   QStringList paths = KGlobal::dirs()->findAllResources("locale", "l10n/*/entry.desktop");
    02216   for(QStringList::ConstIterator it = paths.begin();
    02217       it != paths.end(); ++it)
    02218   {
    02219     QString code = (*it).mid((*it).length()-16, 2);
    02220     if (code != "/C")
    02221        countries.append(code);
    02222   }
    02223   return countries;
    02224 }
    02225
    02226 QString KLocale::twoAlphaToCountryName(const QString &code) const
    02227 {
    02228   KConfig cfg("l10n/"+code.lower()+"/entry.desktop", true, false, "locale");
    02229   cfg.setGroup("KCM Locale");
    02230   return cfg.readEntry("Name");
    02231 }
    02232
    02233 void KLocale::setCalendar(const QString & calType)
    02234 {
    02235   doFormatInit();
    02236
    02237   d->calendarType = calType;
    02238
    02239   delete d->calendar;
    02240   d->calendar = 0;
    02241 }
    02242
    02243 QString KLocale::calendarType() const
    02244 {
    02245   doFormatInit();
    02246
    02247   return d->calendarType;
    02248 }
    02249
    02250 const KCalendarSystem * KLocale::calendar() const
    02251 {
    02252   doFormatInit();
    02253
    02254   // Check if it's the correct calendar?!?
    02255   if ( !d->calendar )
    02256     d->calendar = KCalendarSystemFactory::create( d->calendarType, this );
    02257
    02258   return d->calendar;
    02259 }
    02260
    02261 KLocale::KLocale(const KLocale & rhs)
    02262 {
    02263   d = new KLocalePrivate;
    02264
    02265   *this = rhs;
    02266 }
    02267
    02268 KLocale & KLocale::operator=(const KLocale & rhs)
    02269 {
    02270   // Numbers and money
    02271   m_decimalSymbol = rhs.m_decimalSymbol;
    02272   m_thousandsSeparator = rhs.m_thousandsSeparator;
    02273   m_currencySymbol = rhs.m_currencySymbol;
    02274   m_monetaryDecimalSymbol = rhs.m_monetaryDecimalSymbol;
    02275   m_monetaryThousandsSeparator = rhs.m_monetaryThousandsSeparator;
    02276   m_positiveSign = rhs.m_positiveSign;
    02277   m_negativeSign = rhs.m_negativeSign;
    02278   m_fracDigits = rhs.m_fracDigits;
    02279   m_positivePrefixCurrencySymbol = rhs.m_positivePrefixCurrencySymbol;
    02280   m_negativePrefixCurrencySymbol = rhs.m_negativePrefixCurrencySymbol;
    02281   m_positiveMonetarySignPosition = rhs.m_positiveMonetarySignPosition;
    02282   m_negativeMonetarySignPosition = rhs.m_negativeMonetarySignPosition;
    02283
    02284   // Date and time
    02285   m_timeFormat = rhs.m_timeFormat;
    02286   m_dateFormat = rhs.m_dateFormat;
    02287   m_dateFormatShort = rhs.m_dateFormatShort;
    02288
    02289   m_language = rhs.m_language;
    02290   m_country = rhs.m_country;
    02291
    02292   // the assignment operator works here
    02293   *d = *rhs.d;
    02294   d->languages = 0; // Don't copy languages
    02295   d->calendar = 0; // Don't copy the calendar
    02296
    02297   return *this;
    02298 }
    02299
    02300 bool KLocale::setCharset(const QString & ) { return true; }
    02301 QString KLocale::charset() const { return QString::fromLatin1("UTF-8"); }
    02302
    02303 // KDE4: remove
    02304 #if 0
    02305 void nothing() { i18n("&Next"); }
    02306 #endif

This file is part of the documentation for kdecore Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:18:09 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003