kdecore Library API Documentation

klocale.cpp

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