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