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