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