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