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 static const char * const SYSTEM_MESSAGES = "kdelibs";
00047
00048 static const char *maincatalogue = 0;
00049
00050 class KLocalePrivate
00051 {
00052 public:
00053 int weekStartDay;
00054 bool nounDeclension;
00055 bool dateMonthNamePossessive;
00056 QStringList languageList;
00057 QStringList catalogNames;
00058 QValueList<KCatalogue> catalogues;
00059 QString encoding;
00060 QTextCodec * codecForEncoding;
00061 KConfig * config;
00062 bool formatInited;
00063 int pageSize;
00064 KLocale::MeasureSystem measureSystem;
00065 QStringList langTwoAlpha;
00066 KConfig *languages;
00067
00068 QString calendarType;
00069 KCalendarSystem * calendar;
00070 bool utf8FileEncoding;
00071 QString appName;
00072 };
00073
00074 static KLocale *this_klocale = 0;
00075
00076 KLocale::KLocale( const QString & catalog, KConfig * config )
00077 {
00078 d = new KLocalePrivate;
00079 d->config = config;
00080 d->languages = 0;
00081 d->calendar = 0;
00082 d->formatInited = false;
00083
00084 initEncoding(0);
00085 initFileNameEncoding(0);
00086
00087 KConfig *cfg = d->config;
00088 this_klocale = this;
00089 if (!cfg) cfg = KGlobal::instance()->config();
00090 this_klocale = 0;
00091 Q_ASSERT( cfg );
00092
00093 d->appName = catalog;
00094 initLanguageList( cfg, config == 0);
00095 initMainCatalogues(catalog);
00096 }
00097
00098 QString KLocale::_initLanguage(KConfigBase *config)
00099 {
00100 if (this_klocale)
00101 {
00102
00103 this_klocale->initLanguageList((KConfig *) config, true);
00104
00105 return this_klocale->language();
00106 }
00107 return QString::null;
00108 }
00109
00110 void KLocale::initMainCatalogues(const QString & catalog)
00111 {
00112
00113 QString mainCatalogue = catalog;
00114 if (maincatalogue)
00115 mainCatalogue = QString::fromLatin1(maincatalogue);
00116
00117 if (mainCatalogue.isEmpty()) {
00118 kdDebug(173) << "KLocale instance created called without valid "
00119 << "catalog! Give an argument or call setMainCatalogue "
00120 << "before init" << endl;
00121 }
00122 else {
00123
00124 d->catalogNames.append( mainCatalogue );
00125 d->catalogNames.append( SYSTEM_MESSAGES );
00126 d->catalogNames.append( "kio" );
00127 updateCatalogues();
00128 }
00129 }
00130
00131 void KLocale::initLanguageList(KConfig * config, bool useEnv)
00132 {
00133 KConfigGroupSaver saver(config, "Locale");
00134
00135 m_country = config->readEntry( "Country" );
00136 if ( m_country.isEmpty() )
00137 m_country = defaultCountry();
00138
00139
00140 QStringList languageList;
00141 if ( useEnv )
00142 languageList += QStringList::split
00143 (':', QFile::decodeName( ::getenv("KDE_LANG") ));
00144
00145
00146 if ( useEnv )
00147 {
00148
00149 QStringList langs;
00150
00151 langs << QFile::decodeName( ::getenv("LC_ALL") );
00152 langs << QFile::decodeName( ::getenv("LC_MESSAGES") );
00153 langs << QFile::decodeName( ::getenv("LANG") );
00154
00155 for ( QStringList::Iterator it = langs.begin();
00156 it != langs.end();
00157 ++it )
00158 {
00159 QString ln, ct, chrset;
00160 splitLocale(*it, ln, ct, chrset);
00161
00162 if ( *it == "C" || *it == "POSIX")
00163 {
00164 ln=defaultLanguage();
00165 ct=QString::null;
00166 chrset=QString::null;
00167 }
00168
00169 if (!ct.isEmpty()) {
00170 langs.insert(it, ln + '_' + ct);
00171 }
00172
00173 langs.insert(it, ln);
00174 if (!chrset.isEmpty())
00175 langs.insert(it, ln + '_' + ct + '.' + chrset);
00176 }
00177
00178 languageList += langs;
00179 }
00180
00181 languageList += config->readListEntry("Language", ':');
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 EXPECT_LENGTH( 3 );
00886 if ( n%100 == 1 )
00887 return put_n_in( forms[0], n);
00888 else if (( n%100 >= 2 ) && ( n%100 <= 4 ))
00889 return put_n_in( forms[1], n);
00890 else
00891 return put_n_in( forms[2], n);
00892 case 9:
00893 EXPECT_LENGTH( 3 );
00894 if ( n == 1 )
00895 return put_n_in( forms[0], n);
00896 else if (( n >= 2 ) && ( n <= 4 ))
00897 return put_n_in( forms[1], n);
00898 else
00899 return put_n_in( forms[2], n);
00900 case 10:
00901 EXPECT_LENGTH( 4 );
00902 if ( n == 1 )
00903 return put_n_in( forms[0], n );
00904 else if ( ( n == 0 ) || ( n%100 > 0 && n%100 <= 10 ) )
00905 return put_n_in( forms[1], n );
00906 else if ( n%100 > 10 && n%100 < 20 )
00907 return put_n_in( forms[2], n );
00908 else
00909 return put_n_in( forms[3], n );
00910 case 11:
00911 EXPECT_LENGTH( 4 );
00912 if (n == 1)
00913 return put_n_in(forms[0], n);
00914 else if (n == 2)
00915 return put_n_in(forms[1], n);
00916 else if ( n < 11)
00917 return put_n_in(forms[2], n);
00918 else
00919 return put_n_in(forms[3], n);
00920 case 12:
00921 EXPECT_LENGTH( 3 );
00922 if (n != 11 && n % 10 == 1)
00923 return put_n_in(forms[0], n);
00924 else if (n / 10 != 1 && n % 10 >= 2 && n % 10 <= 4)
00925 return put_n_in(forms[1], n);
00926 else
00927 return put_n_in(forms[2], n);
00928 case 13:
00929 EXPECT_LENGTH(3);
00930 if (n % 10 == 1)
00931 return put_n_in(forms[0], n);
00932 else if (n % 10 == 2)
00933 return put_n_in(forms[1], n);
00934 else
00935 return put_n_in(forms[2], n);
00936 case 14:
00937 EXPECT_LENGTH(5);
00938 if (n == 1)
00939 return put_n_in(forms[0], n);
00940 else if (n == 2)
00941 return put_n_in(forms[1], n);
00942 else if (n < 7)
00943 return put_n_in(forms[2], n);
00944 else if (n < 11)
00945 return put_n_in(forms[3], n);
00946 else
00947 return put_n_in(forms[4], n);
00948 }
00949 kdFatal() << "The function should have been returned in another way\n";
00950
00951 return QString::null;
00952 }
00953
00954 QString KLocale::translateQt( const char *context, const char *source,
00955 const char *message) const
00956 {
00957 if (!source || !source[0]) {
00958 kdWarning() << "KLocale: trying to look up \"\" in catalog. "
00959 << "Fix the program" << endl;
00960 return QString::null;
00961 }
00962
00963 if ( useDefaultLanguage() ) {
00964 return QString::null;
00965 }
00966
00967 char *newstring = 0;
00968 const char *translation = 0;
00969 QString r;
00970
00971 if ( message && message[0]) {
00972 char *newstring = new char[strlen(source) + strlen(message) + 5];
00973 sprintf(newstring, "_: %s\n%s", source, message);
00974 const char *translation = 0;
00975
00976 r = translate_priv(newstring, source, &translation);
00977 delete [] newstring;
00978 if (translation)
00979 return r;
00980 }
00981
00982 if ( context && context[0] && message && message[0]) {
00983 newstring = new char[strlen(context) + strlen(message) + 5];
00984 sprintf(newstring, "_: %s\n%s", context, message);
00985
00986 r = translate_priv(newstring, source, &translation);
00987 delete [] newstring;
00988 if (translation)
00989 return r;
00990 }
00991
00992 r = translate_priv(source, source, &translation);
00993 if (translation)
00994 return r;
00995 return QString::null;
00996 }
00997
00998 bool KLocale::nounDeclension() const
00999 {
01000 doFormatInit();
01001 return d->nounDeclension;
01002 }
01003
01004 bool KLocale::dateMonthNamePossessive() const
01005 {
01006 doFormatInit();
01007 return d->dateMonthNamePossessive;
01008 }
01009
01010 int KLocale::weekStartDay() const
01011 {
01012 doFormatInit();
01013 return d->weekStartDay;
01014 }
01015
01016 bool KLocale::weekStartsMonday() const
01017 {
01018 doFormatInit();
01019 return (d->weekStartDay==1);
01020 }
01021
01022 QString KLocale::decimalSymbol() const
01023 {
01024 doFormatInit();
01025 return m_decimalSymbol;
01026 }
01027
01028 QString KLocale::thousandsSeparator() const
01029 {
01030 doFormatInit();
01031 return m_thousandsSeparator;
01032 }
01033
01034 QString KLocale::currencySymbol() const
01035 {
01036 doFormatInit();
01037 return m_currencySymbol;
01038 }
01039
01040 QString KLocale::monetaryDecimalSymbol() const
01041 {
01042 doFormatInit();
01043 return m_monetaryDecimalSymbol;
01044 }
01045
01046 QString KLocale::monetaryThousandsSeparator() const
01047 {
01048 doFormatInit();
01049 return m_monetaryThousandsSeparator;
01050 }
01051
01052 QString KLocale::positiveSign() const
01053 {
01054 doFormatInit();
01055 return m_positiveSign;
01056 }
01057
01058 QString KLocale::negativeSign() const
01059 {
01060 doFormatInit();
01061 return m_negativeSign;
01062 }
01063
01064 int KLocale::fracDigits() const
01065 {
01066 doFormatInit();
01067 return m_fracDigits;
01068 }
01069
01070 bool KLocale::positivePrefixCurrencySymbol() const
01071 {
01072 doFormatInit();
01073 return m_positivePrefixCurrencySymbol;
01074 }
01075
01076 bool KLocale::negativePrefixCurrencySymbol() const
01077 {
01078 doFormatInit();
01079 return m_negativePrefixCurrencySymbol;
01080 }
01081
01082 KLocale::SignPosition KLocale::positiveMonetarySignPosition() const
01083 {
01084 doFormatInit();
01085 return m_positiveMonetarySignPosition;
01086 }
01087
01088 KLocale::SignPosition KLocale::negativeMonetarySignPosition() const
01089 {
01090 doFormatInit();
01091 return m_negativeMonetarySignPosition;
01092 }
01093
01094 static inline void put_it_in( QChar *buffer, uint& index, const QString &s )
01095 {
01096 for ( uint l = 0; l < s.length(); l++ )
01097 buffer[index++] = s.at( l );
01098 }
01099
01100 static inline void put_it_in( QChar *buffer, uint& index, int number )
01101 {
01102 buffer[index++] = number / 10 + '0';
01103 buffer[index++] = number % 10 + '0';
01104 }
01105
01106 QString KLocale::formatMoney(double num,
01107 const QString & symbol,
01108 int precision) const
01109 {
01110
01111 QString currency = symbol.isNull()
01112 ? currencySymbol()
01113 : symbol;
01114 if (precision < 0) precision = fracDigits();
01115
01116
01117 bool neg = num < 0;
01118 QString res = QString::number(neg?-num:num, 'f', precision);
01119 int pos = res.find('.');
01120 if (pos == -1) pos = res.length();
01121 else res.replace(pos, 1, monetaryDecimalSymbol());
01122
01123 while (0 < (pos -= 3))
01124 res.insert(pos, monetaryThousandsSeparator());
01125
01126
01127 int signpos = neg
01128 ? negativeMonetarySignPosition()
01129 : positiveMonetarySignPosition();
01130 QString sign = neg
01131 ? negativeSign()
01132 : positiveSign();
01133
01134 switch (signpos)
01135 {
01136 case ParensAround:
01137 res.prepend('(');
01138 res.append (')');
01139 break;
01140 case BeforeQuantityMoney:
01141 res.prepend(sign);
01142 break;
01143 case AfterQuantityMoney:
01144 res.append(sign);
01145 break;
01146 case BeforeMoney:
01147 currency.prepend(sign);
01148 break;
01149 case AfterMoney:
01150 currency.append(sign);
01151 break;
01152 }
01153
01154 if (neg?negativePrefixCurrencySymbol():
01155 positivePrefixCurrencySymbol())
01156 {
01157 res.prepend(' ');
01158 res.prepend(currency);
01159 } else {
01160 res.append (' ');
01161 res.append (currency);
01162 }
01163
01164 return res;
01165 }
01166
01167 QString KLocale::formatMoney(const QString &numStr) const
01168 {
01169 return formatMoney(numStr.toDouble());
01170 }
01171
01172 QString KLocale::formatNumber(double num, int precision) const
01173 {
01174 bool neg = num < 0;
01175 if (precision == -1) precision = 2;
01176 QString res = QString::number(neg?-num:num, 'f', precision);
01177 int pos = res.find('.');
01178 if (pos == -1) pos = res.length();
01179 else res.replace(pos, 1, decimalSymbol());
01180
01181 while (0 < (pos -= 3))
01182 res.insert(pos, thousandsSeparator());
01183
01184
01185 res.prepend(neg?negativeSign():positiveSign());
01186
01187 return res;
01188 }
01189
01190 QString KLocale::formatLong(long num) const
01191 {
01192 return formatNumber((double)num, 0);
01193 }
01194
01195 QString KLocale::formatNumber(const QString &numStr) const
01196 {
01197 return formatNumber(numStr.toDouble());
01198 }
01199
01200 QString KLocale::formatDate(const QDate &pDate, bool shortFormat) const
01201 {
01202 const QString rst = shortFormat?dateFormatShort():dateFormat();
01203
01204 QString buffer;
01205
01206 if ( ! pDate.isValid() ) return buffer;
01207
01208 bool escape = false;
01209
01210 int year = calendar()->year(pDate);
01211 int month = calendar()->month(pDate);
01212
01213 for ( uint format_index = 0; format_index < rst.length(); ++format_index )
01214 {
01215 if ( !escape )
01216 {
01217 if ( rst.at( format_index ).unicode() == '%' )
01218 escape = true;
01219 else
01220 buffer.append(rst.at(format_index));
01221 }
01222 else
01223 {
01224 switch ( rst.at( format_index ).unicode() )
01225 {
01226 case '%':
01227 buffer.append('%');
01228 break;
01229 case 'Y':
01230 buffer.append(calendar()->yearString(pDate, false));
01231 break;
01232 case 'y':
01233 buffer.append(calendar()->yearString(pDate, true));
01234 break;
01235 case 'n':
01236 buffer.append(calendar()->monthString(pDate, true));
01237 break;
01238 case 'e':
01239 buffer.append(calendar()->dayString(pDate, true));
01240 break;
01241 case 'm':
01242 buffer.append(calendar()->monthString(pDate, false));
01243 break;
01244 case 'b':
01245 if (d->nounDeclension && d->dateMonthNamePossessive)
01246 buffer.append(calendar()->monthNamePossessive(month, year, true));
01247 else
01248 buffer.append(calendar()->monthName(month, year, true));
01249 break;
01250 case 'B':
01251 if (d->nounDeclension && d->dateMonthNamePossessive)
01252 buffer.append(calendar()->monthNamePossessive(month, year, false));
01253 else
01254 buffer.append(calendar()->monthName(month, year, false));
01255 break;
01256 case 'd':
01257 buffer.append(calendar()->dayString(pDate, false));
01258 break;
01259 case 'a':
01260 buffer.append(calendar()->weekDayName(pDate, true));
01261 break;
01262 case 'A':
01263 buffer.append(calendar()->weekDayName(pDate, false));
01264 break;
01265 default:
01266 buffer.append(rst.at(format_index));
01267 break;
01268 }
01269 escape = false;
01270 }
01271 }
01272 return buffer;
01273 }
01274
01275 void KLocale::setMainCatalogue(const char *catalog)
01276 {
01277 maincatalogue = catalog;
01278 }
01279
01280 double KLocale::readNumber(const QString &_str, bool * ok) const
01281 {
01282 QString str = _str.stripWhiteSpace();
01283 bool neg = str.find(negativeSign()) == 0;
01284 if (neg)
01285 str.remove( 0, negativeSign().length() );
01286
01287
01288
01289
01290 QString exponentialPart;
01291 int EPos;
01292
01293 EPos = str.find('E', 0, false);
01294
01295 if (EPos != -1)
01296 {
01297 exponentialPart = str.mid(EPos);
01298 str = str.left(EPos);
01299 }
01300
01301 int pos = str.find(decimalSymbol());
01302 QString major;
01303 QString minor;
01304 if ( pos == -1 )
01305 major = str;
01306 else
01307 {
01308 major = str.left(pos);
01309 minor = str.mid(pos + decimalSymbol().length());
01310 }
01311
01312
01313 int thlen = thousandsSeparator().length();
01314 int lastpos = 0;
01315 while ( ( pos = major.find( thousandsSeparator() ) ) > 0 )
01316 {
01317
01318 int fromEnd = major.length() - pos;
01319 if ( fromEnd % (3+thlen) != 0
01320 || pos - lastpos > 3
01321 || pos == 0
01322 || (lastpos>0 && pos-lastpos!=3))
01323 {
01324 if (ok) *ok = false;
01325 return 0.0;
01326 }
01327
01328 lastpos = pos;
01329 major.remove( pos, thlen );
01330 }
01331 if (lastpos>0 && major.length()-lastpos!=3)
01332 {
01333 if (ok) *ok = false;
01334 return 0.0;
01335 }
01336
01337 QString tot;
01338 if (neg) tot = '-';
01339
01340 tot += major + '.' + minor + exponentialPart;
01341
01342 return tot.toDouble(ok);
01343 }
01344
01345 double KLocale::readMoney(const QString &_str, bool * ok) const
01346 {
01347 QString str = _str.stripWhiteSpace();
01348 bool neg = false;
01349 bool currencyFound = false;
01350
01351 int pos = str.find(currencySymbol());
01352 if ( pos == 0 || pos == (int) str.length()-1 )
01353 {
01354 str.remove(pos,currencySymbol().length());
01355 str = str.stripWhiteSpace();
01356 currencyFound = true;
01357 }
01358 if (str.isEmpty())
01359 {
01360 if (ok) *ok = false;
01361 return 0;
01362 }
01363
01364
01365 if (negativeMonetarySignPosition() == ParensAround)
01366 {
01367 if (str[0] == '(' && str[str.length()-1] == ')')
01368 {
01369 neg = true;
01370 str.remove(str.length()-1,1);
01371 str.remove(0,1);
01372 }
01373 }
01374 else
01375 {
01376 int i1 = str.find(negativeSign());
01377 if ( i1 == 0 || i1 == (int) str.length()-1 )
01378 {
01379 neg = true;
01380 str.remove(i1,negativeSign().length());
01381 }
01382 }
01383 if (neg) str = str.stripWhiteSpace();
01384
01385
01386
01387 if ( !currencyFound )
01388 {
01389 pos = str.find(currencySymbol());
01390 if ( pos == 0 || pos == (int) str.length()-1 )
01391 {
01392 str.remove(pos,currencySymbol().length());
01393 str = str.stripWhiteSpace();
01394 }
01395 }
01396
01397
01398 pos = str.find(monetaryDecimalSymbol());
01399 QString major;
01400 QString minior;
01401 if (pos == -1)
01402 major = str;
01403 else
01404 {
01405 major = str.left(pos);
01406 minior = str.mid(pos + monetaryDecimalSymbol().length());
01407 }
01408
01409
01410 int thlen = monetaryThousandsSeparator().length();
01411 int lastpos = 0;
01412 while ( ( pos = major.find( monetaryThousandsSeparator() ) ) > 0 )
01413 {
01414
01415 int fromEnd = major.length() - pos;
01416 if ( fromEnd % (3+thlen) != 0
01417 || pos - lastpos > 3
01418 || pos == 0
01419 || (lastpos>0 && pos-lastpos!=3))
01420 {
01421 if (ok) *ok = false;
01422 return 0.0;
01423 }
01424 lastpos = pos;
01425 major.remove( pos, thlen );
01426 }
01427 if (lastpos>0 && major.length()-lastpos!=3)
01428 {
01429 if (ok) *ok = false;
01430 return 0.0;
01431 }
01432
01433 QString tot;
01434 if (neg) tot = '-';
01435 tot += major + '.' + minior;
01436 return tot.toDouble(ok);
01437 }
01438
01445 static int readInt(const QString &str, uint &pos)
01446 {
01447 if (!str.at(pos).isDigit()) return -1;
01448 int result = 0;
01449 for (; str.length() > pos && str.at(pos).isDigit(); pos++)
01450 {
01451 result *= 10;
01452 result += str.at(pos).digitValue();
01453 }
01454
01455 return result;
01456 }
01457
01458 QDate KLocale::readDate(const QString &intstr, bool* ok) const
01459 {
01460 QDate date;
01461 date = readDate(intstr, ShortFormat, ok);
01462 if (date.isValid()) return date;
01463 return readDate(intstr, NormalFormat, ok);
01464 }
01465
01466 QDate KLocale::readDate(const QString &intstr, ReadDateFlags flags, bool* ok) const
01467 {
01468 QString fmt = ((flags & ShortFormat) ? dateFormatShort() : dateFormat()).simplifyWhiteSpace();
01469 return readDate( intstr, fmt, ok );
01470 }
01471
01472 QDate KLocale::readDate(const QString &intstr, const QString &fmt, bool* ok) const
01473 {
01474
01475 QString str = intstr.simplifyWhiteSpace().lower();
01476 int day = -1, month = -1;
01477
01478 int year = calendar()->year(QDate::currentDate());
01479 uint strpos = 0;
01480 uint fmtpos = 0;
01481
01482 int iLength;
01483
01484 bool error = false;
01485
01486 while (fmt.length() > fmtpos && str.length() > strpos && !error)
01487 {
01488
01489 QChar c = fmt.at(fmtpos++);
01490
01491 if (c != '%') {
01492 if (c.isSpace() && str.at(strpos).isSpace())
01493 strpos++;
01494 else if (c != str.at(strpos++))
01495 error = true;
01496 }
01497 else
01498 {
01499 int j;
01500
01501 if (str.length() > strpos && str.at(strpos).isSpace())
01502 strpos++;
01503
01504 c = fmt.at(fmtpos++);
01505 switch (c)
01506 {
01507 case 'a':
01508 case 'A':
01509
01510 error = true;
01511 j = 1;
01512 while (error && (j < 8)) {
01513 QString s = calendar()->weekDayName(j, c == 'a').lower();
01514 int len = s.length();
01515 if (str.mid(strpos, len) == s)
01516 {
01517 strpos += len;
01518 error = false;
01519 }
01520 j++;
01521 }
01522 break;
01523 case 'b':
01524 case 'B':
01525
01526 error = true;
01527 if (d->nounDeclension && d->dateMonthNamePossessive) {
01528 j = 1;
01529 while (error && (j < 13)) {
01530 QString s = calendar()->monthNamePossessive(j, year, c == 'b').lower();
01531 int len = s.length();
01532 if (str.mid(strpos, len) == s) {
01533 month = j;
01534 strpos += len;
01535 error = false;
01536 }
01537 j++;
01538 }
01539 }
01540 j = 1;
01541 while (error && (j < 13)) {
01542 QString s = calendar()->monthName(j, year, c == 'b').lower();
01543 int len = s.length();
01544 if (str.mid(strpos, len) == s) {
01545 month = j;
01546 strpos += len;
01547 error = false;
01548 }
01549 j++;
01550 }
01551 break;
01552 case 'd':
01553 case 'e':
01554 day = calendar()->dayStringToInteger(str.mid(strpos), iLength);
01555 strpos += iLength;
01556
01557 error = iLength <= 0;
01558 break;
01559
01560 case 'n':
01561 case 'm':
01562 month = calendar()->monthStringToInteger(str.mid(strpos), iLength);
01563 strpos += iLength;
01564
01565 error = iLength <= 0;
01566 break;
01567
01568 case 'Y':
01569 case 'y':
01570 year = calendar()->yearStringToInteger(str.mid(strpos), iLength);
01571 strpos += iLength;
01572
01573 error = iLength <= 0;
01574 break;
01575 }
01576 }
01577 }
01578
01579
01580
01581 if ( fmt.length() > fmtpos || str.length() > strpos )
01582 {
01583 error = true;
01584 }
01585
01586
01587 if ( year != -1 && month != -1 && day != -1 && !error)
01588 {
01589 if (ok) *ok = true;
01590
01591 QDate result;
01592 calendar()->setYMD(result, year, month, day);
01593
01594 return result;
01595 }
01596 else
01597 {
01598 if (ok) *ok = false;
01599 return QDate();
01600 }
01601 }
01602
01603 QTime KLocale::readTime(const QString &intstr, bool *ok) const
01604 {
01605 QTime _time;
01606 _time = readTime(intstr, WithSeconds, ok);
01607 if (_time.isValid()) return _time;
01608 return readTime(intstr, WithoutSeconds, ok);
01609 }
01610
01611 QTime KLocale::readTime(const QString &intstr, ReadTimeFlags flags, bool *ok) const
01612 {
01613 QString str = intstr.simplifyWhiteSpace().lower();
01614 QString Format = timeFormat().simplifyWhiteSpace();
01615 if (flags & WithoutSeconds)
01616 Format.remove(QRegExp(".%S"));
01617
01618 int hour = -1, minute = -1;
01619 int second = ( (flags & WithoutSeconds) == 0 ) ? -1 : 0;
01620 bool g_12h = false;
01621 bool pm = false;
01622 uint strpos = 0;
01623 uint Formatpos = 0;
01624
01625 while (Format.length() > Formatpos || str.length() > strpos)
01626 {
01627 if ( !(Format.length() > Formatpos && str.length() > strpos) ) goto error;
01628
01629 QChar c = Format.at(Formatpos++);
01630
01631 if (c != '%')
01632 {
01633 if (c.isSpace())
01634 strpos++;
01635 else if (c != str.at(strpos++))
01636 goto error;
01637 continue;
01638 }
01639
01640
01641 if (str.length() > strpos && str.at(strpos).isSpace())
01642 strpos++;
01643
01644 c = Format.at(Formatpos++);
01645 switch (c)
01646 {
01647 case 'p':
01648 {
01649 QString s;
01650 s = translate("pm").lower();
01651 int len = s.length();
01652 if (str.mid(strpos, len) == s)
01653 {
01654 pm = true;
01655 strpos += len;
01656 }
01657 else
01658 {
01659 s = translate("am").lower();
01660 len = s.length();
01661 if (str.mid(strpos, len) == s) {
01662 pm = false;
01663 strpos += len;
01664 }
01665 else
01666 goto error;
01667 }
01668 }
01669 break;
01670
01671 case 'k':
01672 case 'H':
01673 g_12h = false;
01674 hour = readInt(str, strpos);
01675 if (hour < 0 || hour > 23)
01676 goto error;
01677
01678 break;
01679
01680 case 'l':
01681 case 'I':
01682 g_12h = true;
01683 hour = readInt(str, strpos);
01684 if (hour < 1 || hour > 12)
01685 goto error;
01686
01687 break;
01688
01689 case 'M':
01690 minute = readInt(str, strpos);
01691 if (minute < 0 || minute > 59)
01692 goto error;
01693
01694 break;
01695
01696 case 'S':
01697 second = readInt(str, strpos);
01698 if (second < 0 || second > 59)
01699 goto error;
01700
01701 break;
01702 }
01703 }
01704 if (g_12h) {
01705 hour %= 12;
01706 if (pm) hour += 12;
01707 }
01708
01709 if (ok) *ok = true;
01710 return QTime(hour, minute, second);
01711
01712 error:
01713 if (ok) *ok = false;
01714
01715 return QTime(-1, -1, -1);
01716 }
01717
01718
01719 QString KLocale::formatTime(const QTime &pTime, bool includeSecs) const
01720 {
01721 return formatTime( pTime, includeSecs, false );
01722 }
01723
01724 QString KLocale::formatTime(const QTime &pTime, bool includeSecs, bool isDuration) const
01725 {
01726 const QString rst = timeFormat();
01727
01728
01729
01730 QChar *buffer = new QChar[rst.length() * 3 / 2 + 30];
01731
01732 uint index = 0;
01733 bool escape = false;
01734 int number = 0;
01735
01736 for ( uint format_index = 0; format_index < rst.length(); format_index++ )
01737 {
01738 if ( !escape )
01739 {
01740 if ( rst.at( format_index ).unicode() == '%' )
01741 escape = true;
01742 else
01743 buffer[index++] = rst.at( format_index );
01744 }
01745 else
01746 {
01747 switch ( rst.at( format_index ).unicode() )
01748 {
01749 case '%':
01750 buffer[index++] = '%';
01751 break;
01752 case 'H':
01753 put_it_in( buffer, index, pTime.hour() );
01754 break;
01755 case 'I':
01756 if ( isDuration )
01757 put_it_in( buffer, index, pTime.hour() );
01758 else
01759 put_it_in( buffer, index, ( pTime.hour() + 11) % 12 + 1 );
01760 break;
01761 case 'M':
01762 put_it_in( buffer, index, pTime.minute() );
01763 break;
01764 case 'S':
01765 if (includeSecs)
01766 put_it_in( buffer, index, pTime.second() );
01767 else if ( index > 0 )
01768 {
01769
01770
01771 --index;
01772 break;
01773 }
01774 break;
01775 case 'k':
01776 number = pTime.hour();
01777 case 'l':
01778
01779 if ( rst.at( format_index ).unicode() == 'l' )
01780 number = isDuration ? pTime.hour() : (pTime.hour() + 11) % 12 + 1;
01781 if ( number / 10 )
01782 buffer[index++] = number / 10 + '0';
01783 buffer[index++] = number % 10 + '0';
01784 break;
01785 case 'p':
01786 if ( !isDuration )
01787 {
01788 QString s;
01789 if ( pTime.hour() >= 12 )
01790 put_it_in( buffer, index, translate("pm") );
01791 else
01792 put_it_in( buffer, index, translate("am") );
01793 }
01794 break;
01795 default:
01796 buffer[index++] = rst.at( format_index );
01797 break;
01798 }
01799 escape = false;
01800 }
01801 }
01802 QString ret( buffer, index );
01803 delete [] buffer;
01804 if ( isDuration )
01805 return ret.stripWhiteSpace();
01806 else
01807 return ret;
01808 }
01809
01810 bool KLocale::use12Clock() const
01811 {
01812 if ((timeFormat().contains(QString::fromLatin1("%I")) > 0) ||
01813 (timeFormat().contains(QString::fromLatin1("%l")) > 0))
01814 return true;
01815 else
01816 return false;
01817 }
01818
01819 QString KLocale::languages() const
01820 {
01821 return d->languageList.join( QString::fromLatin1(":") );
01822 }
01823
01824 QStringList KLocale::languageList() const
01825 {
01826 return d->languageList;
01827 }
01828
01829 QString KLocale::formatDateTime(const QDateTime &pDateTime,
01830 bool shortFormat,
01831 bool includeSeconds) const
01832 {
01833 return translate("concatenation of dates and time", "%1 %2")
01834 .arg( formatDate( pDateTime.date(), shortFormat ) )
01835 .arg( formatTime( pDateTime.time(), includeSeconds ) );
01836 }
01837
01838 QString i18n(const char* text)
01839 {
01840 register KLocale *instance = KGlobal::locale();
01841 if (instance)
01842 return instance->translate(text);
01843 return QString::fromUtf8(text);
01844 }
01845
01846 QString i18n(const char* index, const char *text)
01847 {
01848 register KLocale *instance = KGlobal::locale();
01849 if (instance)
01850 return instance->translate(index, text);
01851 return QString::fromUtf8(text);
01852 }
01853
01854 QString i18n(const char* singular, const char* plural, unsigned long n)
01855 {
01856 register KLocale *instance = KGlobal::locale();
01857 if (instance)
01858 return instance->translate(singular, plural, n);
01859 if (n == 1)
01860 return put_n_in(QString::fromUtf8(singular), n);
01861 else
01862 return put_n_in(QString::fromUtf8(plural), n);
01863 }
01864
01865 void KLocale::initInstance()
01866 {
01867 if (KGlobal::_locale)
01868 return;
01869
01870 KInstance *app = KGlobal::instance();
01871 if (app) {
01872 KGlobal::_locale = new KLocale(QString::fromLatin1(app->instanceName()));
01873
01874
01875 QTextCodec::setCodecForLocale(KGlobal::_locale->codecForEncoding());
01876 }
01877 else
01878 kdDebug(173) << "no app name available using KLocale - nothing to do\n";
01879 }
01880
01881 QString KLocale::langLookup(const QString &fname, const char *rtype)
01882 {
01883 QStringList search;
01884
01885
01886 const QStringList localDoc = KGlobal::dirs()->resourceDirs(rtype);
01887
01888
01889 for (int id=localDoc.count()-1; id >= 0; --id)
01890 {
01891 QStringList langs = KGlobal::locale()->languageList();
01892 langs.append( "en" );
01893 langs.remove( defaultLanguage() );
01894 QStringList::ConstIterator lang;
01895 for (lang = langs.begin(); lang != langs.end(); ++lang)
01896 search.append(QString("%1%2/%3").arg(localDoc[id]).arg(*lang).arg(fname));
01897 }
01898
01899
01900 QStringList::Iterator it;
01901 for (it = search.begin(); it != search.end(); ++it)
01902 {
01903 kdDebug(173) << "Looking for help in: " << *it << endl;
01904
01905 QFileInfo info(*it);
01906 if (info.exists() && info.isFile() && info.isReadable())
01907 return *it;
01908 }
01909
01910 return QString::null;
01911 }
01912
01913 bool KLocale::useDefaultLanguage() const
01914 {
01915 return language() == defaultLanguage();
01916 }
01917
01918 void KLocale::initEncoding(KConfig *)
01919 {
01920 const int mibDefault = 4;
01921
01922
01923 setEncoding( QTextCodec::codecForLocale()->mibEnum() );
01924
01925 if ( !d->codecForEncoding )
01926 {
01927 kdWarning(173) << " Defaulting to ISO 8859-1 encoding." << endl;
01928 setEncoding(mibDefault);
01929 }
01930
01931 Q_ASSERT( d->codecForEncoding );
01932 }
01933
01934 void KLocale::initFileNameEncoding(KConfig *)
01935 {
01936
01937
01938 d->utf8FileEncoding = getenv("KDE_UTF8_FILENAMES") != 0;
01939 if (d->utf8FileEncoding)
01940 {
01941 QFile::setEncodingFunction(KLocale::encodeFileNameUTF8);
01942 QFile::setDecodingFunction(KLocale::decodeFileNameUTF8);
01943 }
01944
01945
01946 }
01947
01948 QCString KLocale::encodeFileNameUTF8( const QString & fileName )
01949 {
01950 return fileName.utf8();
01951 }
01952
01953 QString KLocale::decodeFileNameUTF8( const QCString & localFileName )
01954 {
01955 return QString::fromUtf8(localFileName);
01956 }
01957
01958 void KLocale::setDateFormat(const QString & format)
01959 {
01960 doFormatInit();
01961 m_dateFormat = format.stripWhiteSpace();
01962 }
01963
01964 void KLocale::setDateFormatShort(const QString & format)
01965 {
01966 doFormatInit();
01967 m_dateFormatShort = format.stripWhiteSpace();
01968 }
01969
01970 void KLocale::setDateMonthNamePossessive(bool possessive)
01971 {
01972 doFormatInit();
01973 d->dateMonthNamePossessive = possessive;
01974 }
01975
01976 void KLocale::setTimeFormat(const QString & format)
01977 {
01978 doFormatInit();
01979 m_timeFormat = format.stripWhiteSpace();
01980 }
01981
01982 void KLocale::setWeekStartsMonday(bool start)
01983 {
01984 doFormatInit();
01985 if (start)
01986 d->weekStartDay = 1;
01987 else
01988 d->weekStartDay = 7;
01989 }
01990
01991 void KLocale::setWeekStartDay(int day)
01992 {
01993 doFormatInit();
01994 if (day>7 || day<1)
01995 d->weekStartDay = 1;
01996 else
01997 d->weekStartDay = day;
01998 }
01999
02000 QString KLocale::dateFormat() const
02001 {
02002 doFormatInit();
02003 return m_dateFormat;
02004 }
02005
02006 QString KLocale::dateFormatShort() const
02007 {
02008 doFormatInit();
02009 return m_dateFormatShort;
02010 }
02011
02012 QString KLocale::timeFormat() const
02013 {
02014 doFormatInit();
02015 return m_timeFormat;
02016 }
02017
02018 void KLocale::setDecimalSymbol(const QString & symbol)
02019 {
02020 doFormatInit();
02021 m_decimalSymbol = symbol.stripWhiteSpace();
02022 }
02023
02024 void KLocale::setThousandsSeparator(const QString & separator)
02025 {
02026 doFormatInit();
02027
02028 m_thousandsSeparator = separator;
02029 }
02030
02031 void KLocale::setPositiveSign(const QString & sign)
02032 {
02033 doFormatInit();
02034 m_positiveSign = sign.stripWhiteSpace();
02035 }
02036
02037 void KLocale::setNegativeSign(const QString & sign)
02038 {
02039 doFormatInit();
02040 m_negativeSign = sign.stripWhiteSpace();
02041 }
02042
02043 void KLocale::setPositiveMonetarySignPosition(SignPosition signpos)
02044 {
02045 doFormatInit();
02046 m_positiveMonetarySignPosition = signpos;
02047 }
02048
02049 void KLocale::setNegativeMonetarySignPosition(SignPosition signpos)
02050 {
02051 doFormatInit();
02052 m_negativeMonetarySignPosition = signpos;
02053 }
02054
02055 void KLocale::setPositivePrefixCurrencySymbol(bool prefix)
02056 {
02057 doFormatInit();
02058 m_positivePrefixCurrencySymbol = prefix;
02059 }
02060
02061 void KLocale::setNegativePrefixCurrencySymbol(bool prefix)
02062 {
02063 doFormatInit();
02064 m_negativePrefixCurrencySymbol = prefix;
02065 }
02066
02067 void KLocale::setFracDigits(int digits)
02068 {
02069 doFormatInit();
02070 m_fracDigits = digits;
02071 }
02072
02073 void KLocale::setMonetaryThousandsSeparator(const QString & separator)
02074 {
02075 doFormatInit();
02076
02077 m_monetaryThousandsSeparator = separator;
02078 }
02079
02080 void KLocale::setMonetaryDecimalSymbol(const QString & symbol)
02081 {
02082 doFormatInit();
02083 m_monetaryDecimalSymbol = symbol.stripWhiteSpace();
02084 }
02085
02086 void KLocale::setCurrencySymbol(const QString & symbol)
02087 {
02088 doFormatInit();
02089 m_currencySymbol = symbol.stripWhiteSpace();
02090 }
02091
02092 int KLocale::pageSize() const
02093 {
02094 doFormatInit();
02095 return d->pageSize;
02096 }
02097
02098 void KLocale::setPageSize(int pageSize)
02099 {
02100
02101 doFormatInit();
02102 d->pageSize = pageSize;
02103 }
02104
02105 KLocale::MeasureSystem KLocale::measureSystem() const
02106 {
02107 doFormatInit();
02108 return d->measureSystem;
02109 }
02110
02111 void KLocale::setMeasureSystem(MeasureSystem value)
02112 {
02113 doFormatInit();
02114 d->measureSystem = value;
02115 }
02116
02117 QString KLocale::defaultLanguage()
02118 {
02119 return QString::fromLatin1("en_US");
02120 }
02121
02122 QString KLocale::defaultCountry()
02123 {
02124 return QString::fromLatin1("C");
02125 }
02126
02127 const char * KLocale::encoding() const
02128 {
02129 return codecForEncoding()->name();
02130 }
02131
02132 int KLocale::encodingMib() const
02133 {
02134 return codecForEncoding()->mibEnum();
02135 }
02136
02137 int KLocale::fileEncodingMib() const
02138 {
02139 if (d->utf8FileEncoding)
02140 return 106;
02141 return codecForEncoding()->mibEnum();
02142 }
02143
02144 QTextCodec * KLocale::codecForEncoding() const
02145 {
02146 return d->codecForEncoding;
02147 }
02148
02149 bool KLocale::setEncoding(int mibEnum)
02150 {
02151 QTextCodec * codec = QTextCodec::codecForMib(mibEnum);
02152 if (codec)
02153 d->codecForEncoding = codec;
02154
02155 return codec != 0;
02156 }
02157
02158 QStringList KLocale::languagesTwoAlpha() const
02159 {
02160 if (d->langTwoAlpha.count())
02161 return d->langTwoAlpha;
02162
02163 const QStringList &origList = languageList();
02164
02165 QStringList result;
02166
02167 KConfig config(QString::fromLatin1("language.codes"), true, false);
02168 config.setGroup("TwoLetterCodes");
02169
02170 for ( QStringList::ConstIterator it = origList.begin();
02171 it != origList.end();
02172 ++it )
02173 {
02174 QString lang = *it;
02175 QStringList langLst;
02176 if (config.hasKey( lang ))
02177 langLst = config.readListEntry( lang );
02178 else
02179 {
02180 int i = lang.find('_');
02181 if (i >= 0)
02182 lang.truncate(i);
02183 langLst << lang;
02184 }
02185
02186 for ( QStringList::ConstIterator langIt = langLst.begin();
02187 langIt != langLst.end();
02188 ++langIt )
02189 {
02190 if ( !(*langIt).isEmpty() && !result.contains( *langIt ) )
02191 result += *langIt;
02192 }
02193 }
02194 d->langTwoAlpha = result;
02195 return result;
02196 }
02197
02198 QStringList KLocale::allLanguagesTwoAlpha() const
02199 {
02200 if (!d->languages)
02201 d->languages = new KConfig("all_languages", true, false, "locale");
02202
02203 return d->languages->groupList();
02204 }
02205
02206 QString KLocale::twoAlphaToLanguageName(const QString &code) const
02207 {
02208 if (!d->languages)
02209 d->languages = new KConfig("all_languages", true, false, "locale");
02210
02211 QString groupName = code;
02212 const int i = groupName.find('_');
02213 groupName.replace(0, i, groupName.left(i).lower());
02214
02215 d->languages->setGroup(groupName);
02216 return d->languages->readEntry("Name");
02217 }
02218
02219 QStringList KLocale::allCountriesTwoAlpha() const
02220 {
02221 QStringList countries;
02222 QStringList paths = KGlobal::dirs()->findAllResources("locale", "l10n/*/entry.desktop");
02223 for(QStringList::ConstIterator it = paths.begin();
02224 it != paths.end(); ++it)
02225 {
02226 QString code = (*it).mid((*it).length()-16, 2);
02227 if (code != "/C")
02228 countries.append(code);
02229 }
02230 return countries;
02231 }
02232
02233 QString KLocale::twoAlphaToCountryName(const QString &code) const
02234 {
02235 KConfig cfg("l10n/"+code.lower()+"/entry.desktop", true, false, "locale");
02236 cfg.setGroup("KCM Locale");
02237 return cfg.readEntry("Name");
02238 }
02239
02240 void KLocale::setCalendar(const QString & calType)
02241 {
02242 doFormatInit();
02243
02244 d->calendarType = calType;
02245
02246 delete d->calendar;
02247 d->calendar = 0;
02248 }
02249
02250 QString KLocale::calendarType() const
02251 {
02252 doFormatInit();
02253
02254 return d->calendarType;
02255 }
02256
02257 const KCalendarSystem * KLocale::calendar() const
02258 {
02259 doFormatInit();
02260
02261
02262 if ( !d->calendar )
02263 d->calendar = KCalendarSystemFactory::create( d->calendarType, this );
02264
02265 return d->calendar;
02266 }
02267
02268 KLocale::KLocale(const KLocale & rhs)
02269 {
02270 d = new KLocalePrivate;
02271
02272 *this = rhs;
02273 }
02274
02275 KLocale & KLocale::operator=(const KLocale & rhs)
02276 {
02277
02278 m_decimalSymbol = rhs.m_decimalSymbol;
02279 m_thousandsSeparator = rhs.m_thousandsSeparator;
02280 m_currencySymbol = rhs.m_currencySymbol;
02281 m_monetaryDecimalSymbol = rhs.m_monetaryDecimalSymbol;
02282 m_monetaryThousandsSeparator = rhs.m_monetaryThousandsSeparator;
02283 m_positiveSign = rhs.m_positiveSign;
02284 m_negativeSign = rhs.m_negativeSign;
02285 m_fracDigits = rhs.m_fracDigits;
02286 m_positivePrefixCurrencySymbol = rhs.m_positivePrefixCurrencySymbol;
02287 m_negativePrefixCurrencySymbol = rhs.m_negativePrefixCurrencySymbol;
02288 m_positiveMonetarySignPosition = rhs.m_positiveMonetarySignPosition;
02289 m_negativeMonetarySignPosition = rhs.m_negativeMonetarySignPosition;
02290
02291
02292 m_timeFormat = rhs.m_timeFormat;
02293 m_dateFormat = rhs.m_dateFormat;
02294 m_dateFormatShort = rhs.m_dateFormatShort;
02295
02296 m_language = rhs.m_language;
02297 m_country = rhs.m_country;
02298
02299
02300 *d = *rhs.d;
02301 d->languages = 0;
02302 d->calendar = 0;
02303
02304 return *this;
02305 }
02306
02307 bool KLocale::setCharset(const QString & ) { return true; }
02308 QString KLocale::charset() const { return QString::fromLatin1("UTF-8"); }
02309
02310
02311 #if 0
02312 void nothing() { i18n("&Next"); }
02313 #endif