kdecore Library API Documentation

klocale.cpp

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