• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KDECore

klocalizedstring.cpp

Go to the documentation of this file.
00001 /*  This file is part of the KDE libraries
00002     Copyright (C) 2006 Chusslove Illich <caslav.ilic@gmx.net>
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 <klocalizedstring.h>
00021 
00022 #include <config.h>
00023 
00024 #include <kglobal.h>
00025 #include <kdebug.h>
00026 #include <klocale.h>
00027 #include <klocale_p.h>
00028 #include <kcomponentdata.h>
00029 #include <klibrary.h>
00030 #include <kstandarddirs.h>
00031 #include <ktranscript_p.h>
00032 #include <ktranslit_p.h>
00033 #include <kuitsemantics_p.h>
00034 #include "kcatalogname_p.h"
00035 
00036 #include <QMutexLocker>
00037 #include <QStringList>
00038 #include <QByteArray>
00039 #include <QChar>
00040 #include <QHash>
00041 #include <QList>
00042 #include <QVector>
00043 
00044 // Truncates string, for output of long messages.
00045 static QString shortenMessage (const QString &str)
00046 {
00047     const int maxlen = 20;
00048     if (str.length() <= maxlen)
00049         return str;
00050     else
00051         return str.left(maxlen).append("...");
00052 }
00053 
00054 typedef qulonglong pluraln;
00055 typedef qlonglong intn;
00056 typedef qulonglong uintn;
00057 typedef double realn;
00058 
00059 class KLocalizedStringPrivateStatics;
00060 
00061 class KLocalizedStringPrivate
00062 {
00063     friend class KLocalizedString;
00064 
00065     QStringList args;
00066     QList<QVariant> vals;
00067     bool numberSet;
00068     pluraln number;
00069     int numberOrd;
00070     QByteArray ctxt;
00071     QHash<QString, QString> dynctxt;
00072     QByteArray msg;
00073     QByteArray plural;
00074 
00075     QString toString (const KLocale *locale) const;
00076     QString selectForEnglish () const;
00077     QString substituteSimple (const QString &trans,
00078                               const QChar &plchar = '%',
00079                               bool partial = false) const;
00080     QString postFormat (const QString &text,
00081                         const QString &lang,
00082                         const QString &lscr,
00083                         const QString &ctxt) const;
00084     QString substituteTranscript (const QString &trans,
00085                                   const QString &lang,
00086                                   const QString &ctry,
00087                                   const QString &lscr,
00088                                   const QString &final,
00089                                   bool &fallback) const;
00090     int resolveInterpolation (const QString &trans, int pos,
00091                               const QString &lang,
00092                               const QString &ctry,
00093                               const QString &lscr,
00094                               const QString &final,
00095                               QString &result,
00096                               bool &fallback) const;
00097     QVariant segmentToValue (const QString &arg) const;
00098     QString postTranscript (const QString &pcall,
00099                             const QString &lang,
00100                             const QString &ctry,
00101                             const QString &lscr,
00102                             const QString &final) const;
00103 
00104     static void notifyCatalogsUpdated (const QStringList &languages,
00105                                        const QList<KCatalogName> &catalogs);
00106     static void loadTranscript ();
00107 };
00108 
00109 class KLocalizedStringPrivateStatics
00110 {
00111     public:
00112 
00113     const QString theFence;
00114     const QString startInterp;
00115     const QString endInterp;
00116     const QChar scriptPlchar;
00117     const QChar scriptVachar;
00118 
00119     const QString scriptDir;
00120     QHash<QString, QStringList> scriptModules;
00121     QList<QStringList> scriptModulesToLoad;
00122 
00123     bool loadTranscriptCalled;
00124     KTranscript *ktrs;
00125 
00126     QHash<QString, KTranslit*> translits;
00127 
00128     QHash<QString, KuitSemantics*> formatters;
00129 
00130     KLocalizedStringPrivateStatics () :
00131         theFence("|/|"),
00132         startInterp("$["),
00133         endInterp("]"),
00134         scriptPlchar('%'),
00135         scriptVachar('^'),
00136 
00137         scriptDir("LC_SCRIPTS"),
00138         scriptModules(),
00139         scriptModulesToLoad(),
00140 
00141         loadTranscriptCalled(false),
00142         ktrs(NULL),
00143 
00144         translits(),
00145 
00146         formatters()
00147     {}
00148 
00149     ~KLocalizedStringPrivateStatics ()
00150     {
00151         // ktrs is handled by KLibLoader.
00152         //delete ktrs;
00153         qDeleteAll(translits);
00154         qDeleteAll(formatters);
00155     }
00156 };
00157 K_GLOBAL_STATIC(KLocalizedStringPrivateStatics, staticsKLSP)
00158 
00159 KLocalizedString::KLocalizedString ()
00160 : d(new KLocalizedStringPrivate)
00161 {
00162     d->numberSet = false;
00163     d->number = 0;
00164     d->numberOrd = 0;
00165 }
00166 
00167 KLocalizedString::KLocalizedString (const char *ctxt,
00168                                     const char *msg, const char *plural)
00169 : d(new KLocalizedStringPrivate)
00170 {
00171     d->ctxt = ctxt;
00172     d->msg = msg;
00173     d->plural = plural;
00174     d->numberSet = false;
00175     d->number = 0;
00176     d->numberOrd = 0;
00177 }
00178 
00179 KLocalizedString::KLocalizedString(const KLocalizedString &rhs)
00180 : d(new KLocalizedStringPrivate(*rhs.d))
00181 {
00182 }
00183 
00184 KLocalizedString& KLocalizedString::operator= (const KLocalizedString &rhs)
00185 {
00186     if (&rhs != this)
00187     {
00188         *d = *rhs.d;
00189     }
00190     return *this;
00191 }
00192 
00193 KLocalizedString::~KLocalizedString ()
00194 {
00195     delete d;
00196 }
00197 
00198 bool KLocalizedString::isEmpty () const
00199 {
00200     return d->msg.isEmpty();
00201 }
00202 
00203 QString KLocalizedString::toString () const
00204 {
00205     return d->toString(KGlobal::locale());
00206 }
00207 
00208 QString KLocalizedString::toString (const KLocale *locale) const
00209 {
00210     return d->toString(locale);
00211 }
00212 
00213 QString KLocalizedStringPrivate::toString (const KLocale *locale) const
00214 {
00215     KLocalizedStringPrivateStatics *s = staticsKLSP;
00216     QMutexLocker lock(kLocaleMutex());
00217 
00218     // Assure the message has been supplied.
00219     if (msg.isEmpty())
00220     {
00221         kDebug(173) << "Trying to convert empty KLocalizedString to QString.";
00222         #ifndef NDEBUG
00223         return QString("(I18N_EMPTY_MESSAGE)");
00224         #else
00225         return QString();
00226         #endif
00227     }
00228 
00229     // Check whether plural argument has been supplied, if message has plural.
00230     if (!plural.isEmpty() && !numberSet)
00231         kDebug(173) << QString("Plural argument to message {%1} not supplied before conversion.")
00232                               .arg(shortenMessage(QString::fromUtf8(msg)));
00233 
00234     // Get raw translation.
00235     QString lang, rawtrans, lscr, ctry;
00236     if (locale != NULL)
00237     {
00238         if (!ctxt.isEmpty() && !plural.isEmpty())
00239             locale->translateRaw(ctxt, msg, plural, number, &lang, &rawtrans);
00240         else if (!plural.isEmpty())
00241             locale->translateRaw(msg, plural, number, &lang, &rawtrans);
00242         else if (!ctxt.isEmpty())
00243             locale->translateRaw(ctxt, msg, &lang, &rawtrans);
00244         else
00245             locale->translateRaw(msg, &lang, &rawtrans);
00246 
00247         ctry = locale->country();
00248 
00249         // Find any higher priority writing script for the current language.
00250         lscr = KTranslit::higherPriorityScript(lang, locale);
00251     }
00252     else
00253     {
00254         lang = KLocale::defaultLanguage();
00255         ctry = "C";
00256         rawtrans = selectForEnglish();
00257     }
00258 
00259     // Set ordinary translation and possibly scripted translation.
00260     QString trans, strans;
00261     int cdpos = rawtrans.indexOf(s->theFence);
00262     if (cdpos > 0)
00263     {
00264         // Script fence has been found, strip the scripted from the
00265         // ordinary translation.
00266         trans = rawtrans.left(cdpos);
00267 
00268         // Scripted translation.
00269         strans = rawtrans.mid(cdpos + s->theFence.length());
00270 
00271         // Try to initialize Transcript if not initialized, and script not empty.
00272         if (   !s->loadTranscriptCalled && !strans.isEmpty()
00273             && locale && locale->useTranscript())
00274         {
00275             if (KGlobal::hasMainComponent())
00276                 loadTranscript();
00277             else
00278                 kDebug(173) << QString("Scripted message {%1} before transcript engine can be loaded.")
00279                                       .arg(shortenMessage(trans));
00280         }
00281     }
00282     else if (cdpos < 0)
00283     {
00284         // No script fence, use translation as is.
00285         trans = rawtrans;
00286     }
00287     else // cdpos == 0
00288     {
00289         // The msgstr starts with the script fence, no ordinary translation.
00290         // This is not allowed, consider message not translated.
00291         kDebug(173) << QString("Scripted message {%1} without ordinary translation, discarded.")
00292                                .arg(shortenMessage(trans)) ;
00293         trans = selectForEnglish();
00294     }
00295 
00296     // Substitute placeholders in ordinary translation.
00297     QString final = substituteSimple(trans);
00298     // Post-format ordinary translation.
00299     final = postFormat(final, lang, lscr, ctxt);
00300 
00301     // If there is also a scripted translation.
00302     if (!strans.isEmpty()) {
00303         // Evaluate scripted translation.
00304         bool fallback;
00305         QString sfinal = substituteTranscript(strans, lang, ctry, lscr, final, fallback);
00306 
00307         // If any translation produced and no fallback requested.
00308         if (!sfinal.isEmpty() && !fallback) {
00309             final = postFormat(sfinal, lang, lscr, ctxt);
00310         }
00311     }
00312 
00313     // Execute any scripted post calls; they cannot modify the final result,
00314     // but are used to set states.
00315     if (s->ktrs != NULL)
00316     {
00317         QStringList pcalls = s->ktrs->postCalls(lang);
00318         foreach(const QString &pcall, pcalls)
00319             postTranscript(pcall, lang, ctry, lscr, final);
00320     }
00321 
00322     return final;
00323 }
00324 
00325 QString KLocalizedStringPrivate::selectForEnglish () const
00326 {
00327     QString trans;
00328 
00329     if (!plural.isEmpty()) {
00330         if (number == 1) {
00331             trans = QString::fromUtf8(msg);
00332         }
00333         else {
00334             trans = QString::fromUtf8(plural);
00335         }
00336     }
00337     else {
00338         trans = QString::fromUtf8(msg);
00339     }
00340 
00341     return trans;
00342 }
00343 
00344 QString KLocalizedStringPrivate::substituteSimple (const QString &trans,
00345                                                    const QChar &plchar,
00346                                                    bool partial) const
00347 {
00348     #ifdef NDEBUG
00349     Q_UNUSED(partial);
00350     #endif
00351 
00352     QStringList tsegs; // text segments per placeholder occurrence
00353     QList<int> plords; // ordinal numbers per placeholder occurrence
00354     #ifndef NDEBUG
00355     QVector<int> ords; // indicates which placeholders are present
00356     #endif
00357     int slen = trans.length();
00358     int spos = 0;
00359     int tpos = trans.indexOf(plchar);
00360     while (tpos >= 0)
00361     {
00362         int ctpos = tpos;
00363 
00364         tpos++;
00365         if (tpos == slen)
00366             break;
00367 
00368         if (trans[tpos].digitValue() > 0) // %0 not considered a placeholder
00369         {
00370             // Get the placeholder ordinal.
00371             int plord = 0;
00372             while (tpos < slen && trans[tpos].digitValue() >= 0)
00373             {
00374                 plord = 10 * plord + trans[tpos].digitValue();
00375                 tpos++;
00376             }
00377             plord--; // ordinals are zero based
00378 
00379             #ifndef NDEBUG
00380             // Perhaps enlarge storage for indicators.
00381             // Note that QVector<int> will initialize new elements to 0,
00382             // as they are supposed to be.
00383             if (plord >= ords.size())
00384                 ords.resize(plord + 1);
00385 
00386             // Indicate that placeholder with computed ordinal is present.
00387             ords[plord] = 1;
00388             #endif
00389 
00390             // Store text segment prior to placeholder and placeholder number.
00391             tsegs.append(trans.mid(spos, ctpos - spos));
00392             plords.append(plord);
00393 
00394             // Position of next text segment.
00395             spos = tpos;
00396         }
00397 
00398         tpos = trans.indexOf(plchar, tpos);
00399     }
00400     // Store last text segment.
00401     tsegs.append(trans.mid(spos));
00402 
00403     #ifndef NDEBUG
00404     // Perhaps enlarge storage for plural-number ordinal.
00405     if (!plural.isEmpty() && numberOrd >= ords.size())
00406         ords.resize(numberOrd + 1);
00407 
00408     // Message might have plural but without plural placeholder, which is an
00409     // allowed state. To ease further logic, indicate that plural placeholder
00410     // is present anyway if message has plural.
00411     if (!plural.isEmpty())
00412         ords[numberOrd] = 1;
00413     #endif
00414 
00415     // Assemble the final string from text segments and arguments.
00416     QString final;
00417     for (int i = 0; i < plords.size(); i++)
00418     {
00419         final.append(tsegs.at(i));
00420         if (plords.at(i) >= args.size())
00421         // too little arguments
00422         {
00423             // put back the placeholder
00424             final.append('%' + QString::number(plords.at(i) + 1));
00425             #ifndef NDEBUG
00426             if (!partial)
00427                 // spoof the message
00428                 final.append("(I18N_ARGUMENT_MISSING)");
00429             #endif
00430         }
00431         else
00432         // just fine
00433             final.append(args.at(plords.at(i)));
00434     }
00435     final.append(tsegs.last());
00436 
00437     #ifndef NDEBUG
00438     if (!partial)
00439     {
00440         // Check that there are no gaps in numbering sequence of placeholders.
00441         bool gaps = false;
00442         for (int i = 0; i < ords.size(); i++)
00443             if (!ords.at(i))
00444             {
00445                 gaps = true;
00446                 kDebug(173) << QString("Placeholder %%1 skipped in message {%2}.")
00447                                       .arg(QString::number(i + 1), shortenMessage(trans));
00448             }
00449         // If no gaps, check for mismatch between number of unique placeholders and
00450         // actually supplied arguments.
00451         if (!gaps && ords.size() != args.size())
00452             kDebug(173) << QString("%1 instead of %2 arguments to message {%3} supplied before conversion.")
00453                                   .arg(args.size()).arg(ords.size()).arg(shortenMessage(trans));
00454 
00455         // Some spoofs.
00456         if (gaps)
00457             final.append("(I18N_GAPS_IN_PLACEHOLDER_SEQUENCE)");
00458         if (ords.size() < args.size())
00459             final.append("(I18N_EXCESS_ARGUMENTS_SUPPLIED)");
00460         if (!plural.isEmpty() && !numberSet)
00461             final.append("(I18N_PLURAL_ARGUMENT_MISSING)");
00462     }
00463     #endif
00464 
00465     return final;
00466 }
00467 
00468 QString KLocalizedStringPrivate::postFormat (const QString &text,
00469                                              const QString &lang,
00470                                              const QString &lscr,
00471                                              const QString &ctxt) const
00472 {
00473     KLocalizedStringPrivateStatics *s = staticsKLSP;
00474     QMutexLocker lock(kLocaleMutex());
00475 
00476     QString final = text;
00477 
00478     // Transform any semantic markup into visual formatting.
00479     if (s->formatters.contains(lang)) {
00480         final = s->formatters[lang]->format(final, ctxt);
00481     }
00482 
00483     // Transliterate to alternative script.
00484     if (s->translits.contains(lang)) {
00485         final = s->translits[lang]->transliterate(final, lscr);
00486     }
00487 
00488     return final;
00489 }
00490 
00491 QString KLocalizedStringPrivate::substituteTranscript (const QString &strans,
00492                                                        const QString &lang,
00493                                                        const QString &ctry,
00494                                                        const QString &lscr,
00495                                                        const QString &final,
00496                                                        bool &fallback) const
00497 {
00498     KLocalizedStringPrivateStatics *s = staticsKLSP;
00499     QMutexLocker lock(kLocaleMutex());
00500 
00501     if (s->ktrs == NULL)
00502         // Scripting engine not available.
00503         return QString();
00504 
00505     // Iterate by interpolations.
00506     QString sfinal;
00507     fallback = false;
00508     int ppos = 0;
00509     int tpos = strans.indexOf(s->startInterp);
00510     while (tpos >= 0)
00511     {
00512         // Resolve substitutions in preceding text.
00513         QString ptext = substituteSimple(strans.mid(ppos, tpos - ppos),
00514                                          s->scriptPlchar, true);
00515         sfinal.append(ptext);
00516 
00517         // Resolve interpolation.
00518         QString result;
00519         bool fallbackLocal;
00520         tpos = resolveInterpolation(strans, tpos, lang, ctry, lscr, final,
00521                                     result, fallbackLocal);
00522 
00523         // If there was a problem in parsing the interpolation, cannot proceed
00524         // (debug info already reported while parsing).
00525         if (tpos < 0) {
00526             return QString();
00527         }
00528         // If fallback has been explicitly requested, indicate global fallback
00529         // but proceed with evaluations (other interpolations may set states).
00530         if (fallbackLocal) {
00531             fallback = true;
00532         }
00533 
00534         // Add evaluated interpolation to the text.
00535         sfinal.append(result);
00536 
00537         // On to next interpolation.
00538         ppos = tpos;
00539         tpos = strans.indexOf(s->startInterp, tpos);
00540     }
00541     // Last text segment.
00542     sfinal.append(substituteSimple(strans.mid(ppos), s->scriptPlchar, true));
00543 
00544     // Return empty string if fallback was requested.
00545     return fallback ? QString() : sfinal;
00546 }
00547 
00548 int KLocalizedStringPrivate::resolveInterpolation (const QString &strans,
00549                                                    int pos,
00550                                                    const QString &lang,
00551                                                    const QString &ctry,
00552                                                    const QString &lscr,
00553                                                    const QString &final,
00554                                                    QString &result,
00555                                                    bool &fallback) const
00556 {
00557     // pos is the position of opening character sequence.
00558     // Returns the position of first character after closing sequence,
00559     // or -1 in case of parsing error.
00560     // result is set to result of Transcript evaluation.
00561     // fallback is set to true if Transcript evaluation requested so.
00562 
00563     KLocalizedStringPrivateStatics *s = staticsKLSP;
00564     QMutexLocker lock(kLocaleMutex());
00565 
00566     result.clear();
00567     fallback = false;
00568 
00569     // Split interpolation into arguments.
00570     QList<QVariant> iargs;
00571     int slen = strans.length();
00572     int islen = s->startInterp.length();
00573     int ielen = s->endInterp.length();
00574     int tpos = pos + s->startInterp.length();
00575     while (1)
00576     {
00577         // Skip whitespace.
00578         while (tpos < slen && strans[tpos].isSpace()) {
00579             ++tpos;
00580         }
00581         if (tpos == slen) {
00582             kDebug(173) << QString("Unclosed interpolation {%1} in message {%2}.")
00583                                   .arg(strans.mid(pos, tpos - pos), shortenMessage(strans));
00584             return -1;
00585         }
00586         if (strans.mid(tpos, ielen) == s->endInterp) {
00587             break; // no more arguments
00588         }
00589 
00590         // Parse argument: may be concatenated from free and quoted text,
00591         // and sub-interpolations.
00592         // Free and quoted segments may contain placeholders, substitute them;
00593         // recurse into sub-interpolations.
00594         // Free segments may be value references, parse and record for
00595         // consideration at the end.
00596         // Mind backslash escapes throughout.
00597         QStringList segs;
00598         QVariant vref;
00599         while (   !strans[tpos].isSpace()
00600                && strans.mid(tpos, ielen) != s->endInterp)
00601         {
00602             if (strans[tpos] == '\'') { // quoted segment
00603                 QString seg;
00604                 ++tpos; // skip opening quote
00605                 // Find closing quote.
00606                 while (tpos < slen && strans[tpos] != '\'') {
00607                     if (strans[tpos] == '\\')
00608                         ++tpos; // escape next character
00609                     seg.append(strans[tpos]);
00610                     ++tpos;
00611                 }
00612                 if (tpos == slen) {
00613                     kDebug(173) << QString("Unclosed quote in interpolation {%1} in message {%2}.")
00614                                         .arg(strans.mid(pos, tpos - pos), shortenMessage(strans));
00615                     return -1;
00616                 }
00617 
00618                 // Append to list of segments, resolving placeholders.
00619                 segs.append(substituteSimple(seg, s->scriptPlchar, true));
00620 
00621                 ++tpos; // skip closing quote
00622             }
00623             else if (strans.mid(tpos, islen) == s->startInterp) { // sub-interpolation
00624                 QString resultLocal;
00625                 bool fallbackLocal;
00626                 tpos = resolveInterpolation(strans, tpos, lang, ctry, lscr, final,
00627                                             resultLocal, fallbackLocal);
00628                 if (tpos < 0) { // unrecoverable problem in sub-interpolation
00629                     // Error reported in the subcall.
00630                     return tpos;
00631                 }
00632                 if (fallbackLocal) { // sub-interpolation requested fallback
00633                     fallback = true;
00634                 }
00635                 segs.append(resultLocal);
00636             }
00637             else { // free segment
00638                 QString seg;
00639                 // Find whitespace, quote, opening or closing sequence.
00640                 while (   tpos < slen
00641                        && !strans[tpos].isSpace() && strans[tpos] != '\''
00642                        && strans.mid(tpos, islen) != s->startInterp
00643                        && strans.mid(tpos, ielen) != s->endInterp)
00644                 {
00645                     if (strans[tpos] == '\\')
00646                         ++tpos; // escape next character
00647                     seg.append(strans[tpos]);
00648                     ++tpos;
00649                 }
00650                 if (tpos == slen) {
00651                     kDebug(173) << QString("Non-terminated interpolation {%1} in message {%2}.")
00652                                         .arg(strans.mid(pos, tpos - pos), shortenMessage(strans));
00653                     return -1;
00654                 }
00655 
00656                 // The free segment may look like a value reference;
00657                 // in that case, record which value it would reference,
00658                 // and add verbatim to the segment list.
00659                 // Otherwise, do a normal substitution on the segment.
00660                 vref = segmentToValue(seg);
00661                 if (vref.isValid()) {
00662                     segs.append(seg);
00663                 }
00664                 else {
00665                     segs.append(substituteSimple(seg, s->scriptPlchar, true));
00666                 }
00667             }
00668         }
00669 
00670         // Append this argument to rest of the arguments.
00671         // If the there was a single text segment and it was a proper value
00672         // reference, add it instead of the joined segments.
00673         // Otherwise, add the joined segments.
00674         if (segs.size() == 1 && vref.isValid()) {
00675             iargs.append(vref);
00676         }
00677         else {
00678             iargs.append(segs.join(""));
00679         }
00680     }
00681     tpos += ielen; // skip to first character after closing sequence
00682 
00683     // NOTE: Why not substitute placeholders (via substituteSimple) in one
00684     // global pass, then handle interpolations in second pass? Because then
00685     // there is the danger of substituted text or sub-interpolations producing
00686     // quotes and escapes themselves, which would mess up the parsing.
00687 
00688     // Evaluate interpolation.
00689     QString msgctxt = QString::fromUtf8(ctxt);
00690     QString msgid = QString::fromUtf8(msg);
00691     QString scriptError;
00692     bool fallbackLocal;
00693     result = s->ktrs->eval(iargs, lang, ctry, lscr,
00694                            msgctxt, dynctxt, msgid,
00695                            args, vals, final, s->scriptModulesToLoad,
00696                            scriptError, fallbackLocal);
00697     // s->scriptModulesToLoad will be cleared during the call.
00698 
00699     if (fallbackLocal) { // evaluation requested fallback
00700         fallback = true;
00701     }
00702     if (!scriptError.isEmpty()) { // problem with evaluation
00703         fallback = true; // also signal fallback
00704         if (!scriptError.isEmpty()) {
00705             kDebug(173) << QString("Interpolation {%1} in {%2} failed: %3")
00706                                   .arg(strans.mid(pos, tpos - pos), shortenMessage(strans), scriptError);
00707         }
00708     }
00709 
00710     return tpos;
00711 }
00712 
00713 QVariant KLocalizedStringPrivate::segmentToValue (const QString &seg) const
00714 {
00715     KLocalizedStringPrivateStatics *s = staticsKLSP;
00716     QMutexLocker lock(kLocaleMutex());
00717 
00718     // Return invalid variant if segment is either not a proper
00719     // value reference, or the reference is out of bounds.
00720 
00721     // Value reference must start with a special character.
00722     if (seg.left(1) != s->scriptVachar) {
00723         return QVariant();
00724     }
00725 
00726     // Reference number must start with 1-9.
00727     // (If numstr is empty, toInt() will return 0.)
00728     QString numstr = seg.mid(1);
00729     if (numstr.left(1).toInt() < 1) {
00730         return QVariant();
00731     }
00732 
00733     // Number must be valid and in bounds.
00734     bool ok;
00735     int index = numstr.toInt(&ok) - 1;
00736     if (!ok || index >= vals.size()) {
00737         return QVariant();
00738     }
00739 
00740     // Passed all hoops.
00741     return vals.at(index);
00742 }
00743 
00744 QString KLocalizedStringPrivate::postTranscript (const QString &pcall,
00745                                                  const QString &lang,
00746                                                  const QString &ctry,
00747                                                  const QString &lscr,
00748                                                  const QString &final) const
00749 {
00750     KLocalizedStringPrivateStatics *s = staticsKLSP;
00751     QMutexLocker lock(kLocaleMutex());
00752 
00753     if (s->ktrs == NULL)
00754         // Scripting engine not available.
00755         // (Though this cannot happen, we wouldn't be here then.)
00756         return QString();
00757 
00758     // Resolve the post call.
00759     QList<QVariant> iargs;
00760     iargs.append(pcall);
00761     QString msgctxt = QString::fromUtf8(ctxt);
00762     QString msgid = QString::fromUtf8(msg);
00763     QString scriptError;
00764     bool fallback;
00765     QString dummy = s->ktrs->eval(iargs, lang, ctry, lscr,
00766                                   msgctxt, dynctxt, msgid,
00767                                   args, vals, final, s->scriptModulesToLoad,
00768                                   scriptError, fallback);
00769     // s->scriptModulesToLoad will be cleared during the call.
00770 
00771     // If the evaluation went wrong.
00772     if (!scriptError.isEmpty())
00773     {
00774         kDebug(173) << QString("Post call {%1} for message {%2} failed: %3")
00775                               .arg(pcall, shortenMessage(msgid), scriptError);
00776         return QString();
00777     }
00778 
00779     return final;
00780 }
00781 
00782 static QString wrapInt (const QString &numstr)
00783 {
00784     return "<"KUIT_NUMINTG">" + numstr + "</"KUIT_NUMINTG">"; //krazy:exclude=doublequote_chars
00785 }
00786 
00787 static QString wrapReal (const QString &numstr)
00788 {
00789     return "<"KUIT_NUMREAL">" + numstr + "</"KUIT_NUMREAL">"; //krazy:exclude=doublequote_chars
00790 }
00791 
00792 KLocalizedString KLocalizedString::subs (int a, int fieldWidth, int base,
00793                                          const QChar &fillChar) const
00794 {
00795     KLocalizedString kls(*this);
00796     if (!kls.d->plural.isEmpty() && !kls.d->numberSet) {
00797         kls.d->number = static_cast<pluraln>(abs(a));
00798         kls.d->numberSet = true;
00799         kls.d->numberOrd = d->args.size();
00800     }
00801     kls.d->args.append(wrapInt(QString("%1").arg(a, fieldWidth, base, fillChar)));
00802     kls.d->vals.append(static_cast<intn>(a));
00803     return kls;
00804 }
00805 
00806 KLocalizedString KLocalizedString::subs (uint a, int fieldWidth, int base,
00807                                          const QChar &fillChar) const
00808 {
00809     KLocalizedString kls(*this);
00810     if (!kls.d->plural.isEmpty() && !kls.d->numberSet) {
00811         kls.d->number = static_cast<pluraln>(a);
00812         kls.d->numberSet = true;
00813         kls.d->numberOrd = d->args.size();
00814     }
00815     kls.d->args.append(wrapInt(QString("%1").arg(a, fieldWidth, base, fillChar)));
00816     kls.d->vals.append(static_cast<uintn>(a));
00817     return kls;
00818 }
00819 
00820 KLocalizedString KLocalizedString::subs (long a, int fieldWidth, int base,
00821                                          const QChar &fillChar) const
00822 {
00823     KLocalizedString kls(*this);
00824     if (!kls.d->plural.isEmpty() && !kls.d->numberSet) {
00825         kls.d->number = static_cast<pluraln>(abs(a));
00826         kls.d->numberSet = true;
00827         kls.d->numberOrd = d->args.size();
00828     }
00829     kls.d->args.append(wrapInt(QString("%1").arg(a, fieldWidth, base, fillChar)));
00830     kls.d->vals.append(static_cast<intn>(a));
00831     return kls;
00832 }
00833 
00834 KLocalizedString KLocalizedString::subs (ulong a, int fieldWidth, int base,
00835                                          const QChar &fillChar) const
00836 {
00837     KLocalizedString kls(*this);
00838     if (!kls.d->plural.isEmpty() && !kls.d->numberSet) {
00839         kls.d->number = static_cast<pluraln>(a);
00840         kls.d->numberSet = true;
00841         kls.d->numberOrd = d->args.size();
00842     }
00843     kls.d->args.append(wrapInt(QString("%1").arg(a, fieldWidth, base, fillChar)));
00844     kls.d->vals.append(static_cast<uintn>(a));
00845     return kls;
00846 }
00847 
00848 KLocalizedString KLocalizedString::subs (qlonglong a, int fieldWidth, int base,
00849                                          const QChar &fillChar) const
00850 {
00851     KLocalizedString kls(*this);
00852     if (!kls.d->plural.isEmpty() && !kls.d->numberSet) {
00853         kls.d->number = static_cast<pluraln>(qAbs(a));
00854         kls.d->numberSet = true;
00855         kls.d->numberOrd = d->args.size();
00856     }
00857     kls.d->args.append(wrapInt(QString("%1").arg(a, fieldWidth, base, fillChar)));
00858     kls.d->vals.append(static_cast<intn>(a));
00859     return kls;
00860 }
00861 
00862 KLocalizedString KLocalizedString::subs (qulonglong a, int fieldWidth, int base,
00863                                          const QChar &fillChar) const
00864 {
00865     KLocalizedString kls(*this);
00866     if (!kls.d->plural.isEmpty() && !kls.d->numberSet) {
00867         kls.d->number = static_cast<pluraln>(a);
00868         kls.d->numberSet = true;
00869         kls.d->numberOrd = d->args.size();
00870     }
00871     kls.d->args.append(wrapInt(QString("%1").arg(a, fieldWidth, base, fillChar)));
00872     kls.d->vals.append(static_cast<uintn>(a));
00873     return kls;
00874 }
00875 
00876 KLocalizedString KLocalizedString::subs (double a, int fieldWidth,
00877                                          char format, int precision,
00878                                          const QChar &fillChar) const
00879 {
00880     KLocalizedString kls(*this);
00881     kls.d->args.append(wrapReal(QString("%1").arg(a, fieldWidth, format, precision, fillChar)));
00882     kls.d->vals.append(static_cast<realn>(a));
00883     return kls;
00884 }
00885 
00886 KLocalizedString KLocalizedString::subs (QChar a, int fieldWidth,
00887                                          const QChar &fillChar) const
00888 {
00889     KLocalizedString kls(*this);
00890     kls.d->args.append(QString("%1").arg(a, fieldWidth, fillChar));
00891     kls.d->vals.append(QString(a));
00892     return kls;
00893 }
00894 
00895 KLocalizedString KLocalizedString::subs (const QString &a, int fieldWidth,
00896                                          const QChar &fillChar) const
00897 {
00898     KLocalizedString kls(*this);
00899     // if (!KuitSemantics::mightBeRichText(a)) { ...
00900     // Do not try to auto-escape non-rich-text alike arguments;
00901     // breaks compatibility with 4.0. Perhaps for KDE 5?
00902     // Perhaps bad idea alltogether (too much surprise)?
00903     kls.d->args.append(QString("%1").arg(a, fieldWidth, fillChar));
00904     kls.d->vals.append(a);
00905     return kls;
00906 }
00907 
00908 KLocalizedString KLocalizedString::inContext (const QString &key,
00909                                               const QString &text) const
00910 {
00911     KLocalizedString kls(*this);
00912     kls.d->dynctxt[key] = text;
00913     return kls;
00914 }
00915 
00916 KLocalizedString ki18n (const char* msg)
00917 {
00918     return KLocalizedString(NULL, msg, NULL);
00919 }
00920 
00921 KLocalizedString ki18nc (const char* ctxt, const char *msg)
00922 {
00923     return KLocalizedString(ctxt, msg, NULL);
00924 }
00925 
00926 KLocalizedString ki18np (const char* singular, const char* plural)
00927 {
00928     return KLocalizedString(NULL, singular, plural);
00929 }
00930 
00931 KLocalizedString ki18ncp (const char* ctxt,
00932                           const char* singular, const char* plural)
00933 {
00934     return KLocalizedString(ctxt, singular, plural);
00935 }
00936 
00937 extern "C"
00938 {
00939     typedef KTranscript *(*InitFunc)();
00940 }
00941 
00942 void KLocalizedStringPrivate::loadTranscript ()
00943 {
00944     KLocalizedStringPrivateStatics *s = staticsKLSP;
00945     QMutexLocker lock(kLocaleMutex());
00946 
00947     s->loadTranscriptCalled = true;
00948     s->ktrs = NULL; // null indicates that Transcript is not available
00949 
00950     KLibrary lib(QLatin1String("ktranscript"));
00951     if (!lib.load()) {
00952         kDebug(173) << "Cannot load transcript plugin:" << lib.errorString();
00953         return;
00954     }
00955 
00956     InitFunc initf = (InitFunc) lib.resolveFunction("load_transcript");
00957     if (!initf) {
00958         lib.unload();
00959         kDebug(173) << "Cannot find function load_transcript in transcript plugin.";
00960         return;
00961     }
00962 
00963     s->ktrs = initf();
00964 }
00965 
00966 void KLocalizedString::notifyCatalogsUpdated (const QStringList &languages,
00967                                               const QList<KCatalogName> &catalogs)
00968 {
00969     KLocalizedStringPrivate::notifyCatalogsUpdated(languages, catalogs);
00970 }
00971 
00972 void KLocalizedStringPrivate::notifyCatalogsUpdated (const QStringList &languages,
00973                                                      const QList<KCatalogName> &catalogs)
00974 {
00975     if (staticsKLSP.isDestroyed()) {
00976         return;
00977     }
00978     KLocalizedStringPrivateStatics *s = staticsKLSP;
00979     // Very important: do not the mutex here.
00980     //QMutexLocker lock(kLocaleMutex());
00981 
00982     // Find script modules for all included language/catalogs that have them,
00983     // and remember their paths.
00984     // A more specific module may reference the calls from a less specific,
00985     // and the catalog list is ordered from more to less specific. Therefore,
00986     // work on reversed list of catalogs.
00987     foreach (const QString &lang, languages) {
00988         for (int i = catalogs.size() - 1; i >= 0; --i) {
00989             const KCatalogName &cat(catalogs[i]);
00990 
00991             // Assemble module's relative path.
00992             QString modrpath =   lang + '/' + s->scriptDir + '/'
00993                             + cat.name + '/' + cat.name + ".js";
00994 
00995             // Try to find this module.
00996             QString modapath = KStandardDirs::locate("locale", modrpath);
00997 
00998             // If the module exists and hasn't been already included.
00999             if (   !modapath.isEmpty()
01000                 && !s->scriptModules[lang].contains(cat.name))
01001             {
01002                 // Indicate that the module has been considered.
01003                 s->scriptModules[lang].append(cat.name);
01004 
01005                 // Store the absolute path and language of the module,
01006                 // to load on next script evaluation.
01007                 QStringList mod;
01008                 mod.append(modapath);
01009                 mod.append(lang);
01010                 s->scriptModulesToLoad.append(mod);
01011             }
01012         }
01013     }
01014 
01015     // Create writing script transliterators for each new language.
01016     foreach (const QString &lang, languages) {
01017         if (!s->translits.contains(lang)) {
01018             KTranslit *t = KTranslit::create(lang);
01019             if (t != NULL) {
01020                 s->translits.insert(lang, t);
01021             }
01022         }
01023     }
01024 
01025     // Create visual formatters for each new language.
01026     foreach (const QString &lang, languages) {
01027         if (!s->formatters.contains(lang)) {
01028             s->formatters.insert(lang, new KuitSemantics(lang));
01029         }
01030     }
01031 }

KDECore

Skip menu "KDECore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal