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