• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

KDECore

klocale.cpp

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

KDECore

Skip menu "KDECore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal