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