KDECore
kcatalog.cpp
Go to the documentation of this file.
00001 /* This file is part of the KDE libraries 00002 Copyright (c) 2001 Hans Petter Bieker <bieker@kde.org> 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Library General Public 00006 License as published by the Free Software Foundation; either 00007 version 2 of the License, or (at your option) any later version. 00008 00009 This library is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 Library General Public License for more details. 00013 00014 You should have received a copy of the GNU Library General Public License 00015 along with this library; see the file COPYING.LIB. If not, write to 00016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00017 Boston, MA 02110-1301, USA. 00018 */ 00019 00020 #include "kcatalog_p.h" 00021 #include "kstandarddirs.h" 00022 00023 #include <config.h> 00024 00025 #include <QtCore/QFile> 00026 #include <QMutexLocker> 00027 00028 #include <kdebug.h> 00029 00030 #include <stdlib.h> 00031 #include <locale.h> 00032 #include "gettext.h" 00033 00034 00035 static bool s_localeSet = false; 00036 00037 // Initialize the locale very early during application startup 00038 // This is necessary for e.g. toLocal8Bit() to work, even before 00039 // a Q[Core]Application exists (David) 00040 int kInitializeLocale() 00041 { 00042 #ifndef _WIN32_WCE 00043 setlocale(LC_ALL, ""); 00044 #endif 00045 extern Q_CORE_EXPORT bool qt_locale_initialized; // in Qt since 4.5.0 00046 qt_locale_initialized = true; // as recommended by Thiago 00047 s_localeSet = true; 00048 return 1; 00049 } 00050 Q_CONSTRUCTOR_FUNCTION(kInitializeLocale) 00051 00052 // not defined on win32 :( 00053 #ifdef _WIN32 00054 # ifndef LC_MESSAGES 00055 # define LC_MESSAGES 42 00056 # endif 00057 #endif 00058 00059 static char *langenv = 0; 00060 static const int langenvMaxlen = 42; 00061 // = "LANGUAGE=" + 32 chars for language code + terminating zero 00062 00063 class KCatalogStaticData 00064 { 00065 public: 00066 KCatalogStaticData() {} 00067 00068 QMutex mutex; 00069 }; 00070 00071 K_GLOBAL_STATIC(KCatalogStaticData, catalogStaticData) 00072 00073 class KCatalogPrivate 00074 { 00075 public: 00076 KCatalogPrivate() 00077 : bindDone(false) 00078 {} 00079 00080 QByteArray language; 00081 QByteArray name; 00082 QByteArray localeDir; 00083 00084 QByteArray systemLanguage; 00085 bool bindDone; 00086 00087 static QByteArray currentLanguage; 00088 00089 void setupGettextEnv (); 00090 void resetSystemLanguage (); 00091 }; 00092 00093 QDebug operator<<(QDebug debug, const KCatalog &c) 00094 { 00095 return debug << c.d->language << " " << c.d->name << " " << c.d->localeDir; 00096 } 00097 00098 QByteArray KCatalogPrivate::currentLanguage; 00099 00100 KCatalog::KCatalog(const QString & name, const QString & language ) 00101 : d( new KCatalogPrivate ) 00102 { 00103 // Set locales if the static initializer didn't work 00104 if (!s_localeSet) { 00105 kInitializeLocale(); 00106 } 00107 00108 // Find locale directory for this catalog. 00109 QString localeDir = catalogLocaleDir( name, language ); 00110 00111 d->language = QFile::encodeName( language ); 00112 d->name = QFile::encodeName( name ); 00113 d->localeDir = QFile::encodeName( localeDir ); 00114 00115 // Always get translations in UTF-8, regardless of user's environment. 00116 bind_textdomain_codeset( d->name, "UTF-8" ); 00117 00118 // Invalidate current language, to trigger binding at next translate call. 00119 KCatalogPrivate::currentLanguage.clear(); 00120 00121 if (!langenv) { 00122 // Call putenv only here, to initialize LANGUAGE variable. 00123 // Later only change langenv to what is currently needed. 00124 langenv = new char[langenvMaxlen]; 00125 QByteArray lang = qgetenv("LANGUAGE"); 00126 snprintf(langenv, langenvMaxlen, "LANGUAGE=%s", lang.constData()); 00127 putenv(langenv); 00128 } 00129 } 00130 00131 KCatalog::KCatalog(const KCatalog & rhs) 00132 : d( new KCatalogPrivate ) 00133 { 00134 *this = rhs; 00135 } 00136 00137 KCatalog & KCatalog::operator=(const KCatalog & rhs) 00138 { 00139 *d = *rhs.d; 00140 00141 return *this; 00142 } 00143 00144 KCatalog::~KCatalog() 00145 { 00146 delete d; 00147 } 00148 00149 QString KCatalog::catalogLocaleDir( const QString &name, 00150 const QString &language ) 00151 { 00152 QString relpath = QString::fromLatin1( "%1/LC_MESSAGES/%2.mo" ) 00153 .arg( language ).arg( name ); 00154 return KGlobal::dirs()->findResourceDir( "locale", relpath ); 00155 } 00156 00157 QString KCatalog::name() const 00158 { 00159 return QFile::decodeName(d->name); 00160 } 00161 00162 QString KCatalog::language() const 00163 { 00164 return QFile::decodeName(d->language); 00165 } 00166 00167 QString KCatalog::localeDir() const 00168 { 00169 return QFile::decodeName(d->localeDir); 00170 } 00171 00172 #ifdef Q_WS_WIN 00173 extern "C" int __declspec(dllimport) _nl_msg_cat_cntr; 00174 #endif 00175 00176 void KCatalogPrivate::setupGettextEnv () 00177 { 00178 // Point Gettext to current language, recording system value for recovery. 00179 systemLanguage = qgetenv("LANGUAGE"); 00180 if (systemLanguage != language) { 00181 // putenv has been called in the constructor, 00182 // it is enough to change the string set there. 00183 snprintf(langenv, langenvMaxlen, "LANGUAGE=%s", language.constData()); 00184 } 00185 00186 // Rebind text domain if language actually changed from the last time, 00187 // as locale directories may differ for different languages of same catalog. 00188 if (language != currentLanguage || !bindDone) { 00189 00190 currentLanguage = language; 00191 bindDone = true; 00192 00193 //kDebug() << "bindtextdomain" << name << localeDir; 00194 bindtextdomain(name, localeDir); 00195 00196 // Magic to make sure Gettext doesn't use stale cached translation 00197 // from previous language. 00198 #ifndef _MSC_VER 00199 extern int _nl_msg_cat_cntr; 00200 #endif 00201 ++_nl_msg_cat_cntr; 00202 } 00203 } 00204 00205 void KCatalogPrivate::resetSystemLanguage () 00206 { 00207 if (language != systemLanguage) { 00208 snprintf(langenv, langenvMaxlen, "LANGUAGE=%s", systemLanguage.constData()); 00209 } 00210 } 00211 00212 QString KCatalog::translate(const char * msgid) const 00213 { 00214 QMutexLocker locker(&catalogStaticData->mutex); 00215 d->setupGettextEnv(); 00216 const char *msgstr = dgettext(d->name, msgid); 00217 d->resetSystemLanguage(); 00218 return QString::fromUtf8(msgstr); 00219 } 00220 00221 QString KCatalog::translate(const char * msgctxt, const char * msgid) const 00222 { 00223 QMutexLocker locker(&catalogStaticData->mutex); 00224 d->setupGettextEnv(); 00225 const char *msgstr = dpgettext_expr(d->name, msgctxt, msgid); 00226 d->resetSystemLanguage(); 00227 return QString::fromUtf8(msgstr); 00228 } 00229 00230 QString KCatalog::translate(const char * msgid, const char * msgid_plural, 00231 unsigned long n) const 00232 { 00233 QMutexLocker locker(&catalogStaticData->mutex); 00234 d->setupGettextEnv(); 00235 const char *msgstr = dngettext(d->name, msgid, msgid_plural, n); 00236 d->resetSystemLanguage(); 00237 return QString::fromUtf8(msgstr); 00238 } 00239 00240 QString KCatalog::translate(const char * msgctxt, const char * msgid, 00241 const char * msgid_plural, unsigned long n) const 00242 { 00243 QMutexLocker locker(&catalogStaticData->mutex); 00244 d->setupGettextEnv(); 00245 const char *msgstr = dnpgettext_expr(d->name, msgctxt, msgid, msgid_plural, n); 00246 d->resetSystemLanguage(); 00247 return QString::fromUtf8(msgstr); 00248 } 00249 00250 QString KCatalog::translateStrict(const char * msgid) const 00251 { 00252 QMutexLocker locker(&catalogStaticData->mutex); 00253 d->setupGettextEnv(); 00254 const char *msgstr = dgettext(d->name, msgid); 00255 d->resetSystemLanguage(); 00256 return msgstr != msgid ? QString::fromUtf8(msgstr) : QString(); 00257 } 00258 00259 QString KCatalog::translateStrict(const char * msgctxt, const char * msgid) const 00260 { 00261 QMutexLocker locker(&catalogStaticData->mutex); 00262 d->setupGettextEnv(); 00263 const char *msgstr = dpgettext_expr(d->name, msgctxt, msgid); 00264 d->resetSystemLanguage(); 00265 return msgstr != msgid ? QString::fromUtf8(msgstr) : QString(); 00266 } 00267 00268 QString KCatalog::translateStrict(const char * msgid, const char * msgid_plural, 00269 unsigned long n) const 00270 { 00271 QMutexLocker locker(&catalogStaticData->mutex); 00272 d->setupGettextEnv(); 00273 const char *msgstr = dngettext(d->name, msgid, msgid_plural, n); 00274 d->resetSystemLanguage(); 00275 return msgstr != msgid && msgstr != msgid_plural ? QString::fromUtf8(msgstr) : QString(); 00276 } 00277 00278 QString KCatalog::translateStrict(const char * msgctxt, const char * msgid, 00279 const char * msgid_plural, unsigned long n) const 00280 { 00281 QMutexLocker locker(&catalogStaticData->mutex); 00282 d->setupGettextEnv(); 00283 const char *msgstr = dnpgettext_expr(d->name, msgctxt, msgid, msgid_plural, n); 00284 d->resetSystemLanguage(); 00285 return msgstr != msgid && msgstr != msgid_plural ? QString::fromUtf8(msgstr) : QString(); 00286 } 00287
KDE 4.6 API Reference