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