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