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