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