kdecore Library API Documentation

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
KDE Logo
This file is part of the documentation for kdecore Library Version 3.4.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Feb 8 08:00:48 2006 by doxygen 1.4.4 written by Dimitri van Heesch, © 1997-2003