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