• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.8.5 API Reference
  • KDE Home
  • Contact Us
 

KDECore

  • kdecore
  • localization
klocalizedstring.cpp
Go to the documentation of this file.
1 /* This file is part of the KDE libraries
2  Copyright (C) 2006 Chusslove Illich <caslav.ilic@gmx.net>
3 
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Library General Public
6  License as published by the Free Software Foundation; either
7  version 2 of the License, or (at your option) any later version.
8 
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  Library General Public License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to
16  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  Boston, MA 02110-1301, USA.
18 */
19 
20 #include <klocalizedstring.h>
21 
22 #include <config.h>
23 
24 #include <kglobal.h>
25 #include <kdebug.h>
26 #include <klocale.h>
27 #include <klocale_p.h>
28 #include <klibrary.h>
29 #include <kstandarddirs.h>
30 #include <ktranscript_p.h>
31 #include <kuitsemantics_p.h>
32 #include "kcatalogname_p.h"
33 
34 #include <QMutexLocker>
35 #include <QStringList>
36 #include <QByteArray>
37 #include <QChar>
38 #include <QHash>
39 #include <QList>
40 #include <QVector>
41 
42 // Truncates string, for output of long messages.
43 static QString shortenMessage (const QString &str)
44 {
45  const int maxlen = 20;
46  if (str.length() <= maxlen)
47  return str;
48  else
49  return str.left(maxlen).append(QLatin1String("..."));
50 }
51 
52 typedef qulonglong pluraln;
53 typedef qlonglong intn;
54 typedef qulonglong uintn;
55 typedef double realn;
56 
57 class KLocalizedStringPrivateStatics;
58 
59 class KLocalizedStringPrivate
60 {
61  friend class KLocalizedString;
62 
63  QStringList args;
64  QList<QVariant> vals;
65  bool numberSet;
66  pluraln number;
67  int numberOrd;
68  QByteArray ctxt;
69  QHash<QString, QString> dynctxt;
70  QByteArray msg;
71  QByteArray plural;
72 
73  QString toString (const KLocale *locale, const QString &catalogName) const;
74  QString selectForEnglish () const;
75  QString substituteSimple (const QString &trans,
76  const QChar &plchar = QLatin1Char('%'),
77  bool partial = false) const;
78  QString postFormat (const QString &text,
79  const QString &lang,
80  const QString &ctxt) const;
81  QString substituteTranscript (const QString &trans,
82  const QString &lang,
83  const QString &ctry,
84  const QString &final,
85  bool &fallback) const;
86  int resolveInterpolation (const QString &trans, int pos,
87  const QString &lang,
88  const QString &ctry,
89  const QString &final,
90  QString &result,
91  bool &fallback) const;
92  QVariant segmentToValue (const QString &arg) const;
93  QString postTranscript (const QString &pcall,
94  const QString &lang,
95  const QString &ctry,
96  const QString &final) const;
97 
98  static void notifyCatalogsUpdated (const QStringList &languages,
99  const QList<KCatalogName> &catalogs);
100  static void loadTranscript ();
101 };
102 
103 class KLocalizedStringPrivateStatics
104 {
105  public:
106 
107  const QString theFence;
108  const QString startInterp;
109  const QString endInterp;
110  const QChar scriptPlchar;
111  const QChar scriptVachar;
112 
113  const QString scriptDir;
114  QHash<QString, QStringList> scriptModules;
115  QList<QStringList> scriptModulesToLoad;
116 
117  bool loadTranscriptCalled;
118  KTranscript *ktrs;
119 
120  QHash<QString, KuitSemantics*> formatters;
121 
122  KLocalizedStringPrivateStatics () :
123  theFence(QLatin1String("|/|")),
124  startInterp(QLatin1String("$[")),
125  endInterp(QLatin1String("]")),
126  scriptPlchar(QLatin1Char('%')),
127  scriptVachar(QLatin1Char('^')),
128 
129  scriptDir(QLatin1String("LC_SCRIPTS")),
130  scriptModules(),
131  scriptModulesToLoad(),
132 
133  loadTranscriptCalled(false),
134  ktrs(NULL),
135 
136  formatters()
137  {}
138 
139  ~KLocalizedStringPrivateStatics ()
140  {
141  // ktrs is handled by KLibLoader.
142  //delete ktrs;
143  qDeleteAll(formatters);
144  }
145 };
146 K_GLOBAL_STATIC(KLocalizedStringPrivateStatics, staticsKLSP)
147 
148 KLocalizedString::KLocalizedString ()
149 : d(new KLocalizedStringPrivate)
150 {
151  d->numberSet = false;
152  d->number = 0;
153  d->numberOrd = 0;
154 }
155 
156 KLocalizedString::KLocalizedString (const char *ctxt,
157  const char *msg, const char *plural)
158 : d(new KLocalizedStringPrivate)
159 {
160  d->ctxt = ctxt;
161  d->msg = msg;
162  d->plural = plural;
163  d->numberSet = false;
164  d->number = 0;
165  d->numberOrd = 0;
166 }
167 
168 KLocalizedString::KLocalizedString(const KLocalizedString &rhs)
169 : d(new KLocalizedStringPrivate(*rhs.d))
170 {
171 }
172 
173 KLocalizedString& KLocalizedString::operator= (const KLocalizedString &rhs)
174 {
175  if (&rhs != this)
176  {
177  *d = *rhs.d;
178  }
179  return *this;
180 }
181 
182 KLocalizedString::~KLocalizedString ()
183 {
184  delete d;
185 }
186 
187 bool KLocalizedString::isEmpty () const
188 {
189  return d->msg.isEmpty();
190 }
191 
192 QString KLocalizedString::toString () const
193 {
194  return d->toString(KGlobal::locale(), QString());
195 }
196 
197 QString KLocalizedString::toString (const QString &catalogName) const
198 {
199  return d->toString(KGlobal::locale(), catalogName);
200 }
201 
202 QString KLocalizedString::toString (const KLocale *locale) const
203 {
204  return d->toString(locale, QString());
205 }
206 
207 QString KLocalizedString::toString (const KLocale *locale,
208  const QString &catalogName) const
209 {
210  return d->toString(locale, catalogName);
211 }
212 
213 QString KLocalizedStringPrivate::toString (const KLocale *locale,
214  const QString &catalogName) const
215 {
216  const KLocalizedStringPrivateStatics *s = staticsKLSP;
217 
218  QMutexLocker lock(kLocaleMutex());
219 
220  // Assure the message has been supplied.
221  if (msg.isEmpty())
222  {
223  kDebug(173) << "Trying to convert empty KLocalizedString to QString.";
224  #ifndef NDEBUG
225  return QString::fromLatin1("(I18N_EMPTY_MESSAGE)");
226  #else
227  return QString();
228  #endif
229  }
230 
231  // Check whether plural argument has been supplied, if message has plural.
232  if (!plural.isEmpty() && !numberSet)
233  kDebug(173) << QString::fromLatin1("Plural argument to message {%1} not supplied before conversion.")
234  .arg(shortenMessage(QString::fromUtf8(msg)));
235 
236  // Get raw translation.
237  QString rawtrans, lang, ctry;
238  const char *catname = catalogName.toUtf8();
239  if (locale != NULL) {
240  if (!ctxt.isEmpty() && !plural.isEmpty()) {
241  locale->translateRawFrom(catname, ctxt, msg, plural, number,
242  &lang, &rawtrans);
243  } else if (!plural.isEmpty()) {
244  locale->translateRawFrom(catname, msg, plural, number,
245  &lang, &rawtrans);
246  } else if (!ctxt.isEmpty()) {
247  locale->translateRawFrom(catname, ctxt, msg,
248  &lang, &rawtrans);
249  } else {
250  locale->translateRawFrom(catname, msg,
251  &lang, &rawtrans);
252  }
253  ctry = locale->country();
254  } else {
255  lang = KLocale::defaultLanguage();
256  ctry = QLatin1Char('C');
257  rawtrans = selectForEnglish();
258  }
259 
260  // Set ordinary translation and possibly scripted translation.
261  QString trans, strans;
262  int cdpos = rawtrans.indexOf(s->theFence);
263  if (cdpos > 0)
264  {
265  // Script fence has been found, strip the scripted from the
266  // ordinary translation.
267  trans = rawtrans.left(cdpos);
268 
269  // Scripted translation.
270  strans = rawtrans.mid(cdpos + s->theFence.length());
271 
272  // Try to initialize Transcript if not initialized, and script not empty.
273  if ( !s->loadTranscriptCalled && !strans.isEmpty()
274  && locale && locale->useTranscript())
275  {
276  if (KGlobal::hasMainComponent())
277  loadTranscript();
278  else
279  kDebug(173) << QString::fromLatin1("Scripted message {%1} before transcript engine can be loaded.")
280  .arg(shortenMessage(trans));
281  }
282  }
283  else if (cdpos < 0)
284  {
285  // No script fence, use translation as is.
286  trans = rawtrans;
287  }
288  else // cdpos == 0
289  {
290  // The msgstr starts with the script fence, no ordinary translation.
291  // This is not allowed, consider message not translated.
292  kDebug(173) << QString::fromLatin1("Scripted message {%1} without ordinary translation, discarded.")
293  .arg(shortenMessage(trans)) ;
294  trans = selectForEnglish();
295  }
296 
297  // Substitute placeholders in ordinary translation.
298  QString final = substituteSimple(trans);
299  // Post-format ordinary translation.
300  final = postFormat(final, lang, QString::fromLatin1(ctxt));
301 
302  // If there is also a scripted translation.
303  if (!strans.isEmpty()) {
304  // Evaluate scripted translation.
305  bool fallback;
306  QString sfinal = substituteTranscript(strans, lang, ctry, final, fallback);
307 
308  // If any translation produced and no fallback requested.
309  if (!sfinal.isEmpty() && !fallback) {
310  final = postFormat(sfinal, lang, QString::fromLatin1(ctxt));
311  }
312  }
313 
314  // Execute any scripted post calls; they cannot modify the final result,
315  // but are used to set states.
316  if (s->ktrs != NULL)
317  {
318  QStringList pcalls = s->ktrs->postCalls(lang);
319  foreach(const QString &pcall, pcalls)
320  postTranscript(pcall, lang, ctry, final);
321  }
322 
323  return final;
324 }
325 
326 QString KLocalizedStringPrivate::selectForEnglish () const
327 {
328  QString trans;
329 
330  if (!plural.isEmpty()) {
331  if (number == 1) {
332  trans = QString::fromUtf8(msg);
333  }
334  else {
335  trans = QString::fromUtf8(plural);
336  }
337  }
338  else {
339  trans = QString::fromUtf8(msg);
340  }
341 
342  return trans;
343 }
344 
345 QString KLocalizedStringPrivate::substituteSimple (const QString &trans,
346  const QChar &plchar,
347  bool partial) const
348 {
349  #ifdef NDEBUG
350  Q_UNUSED(partial);
351  #endif
352 
353  QStringList tsegs; // text segments per placeholder occurrence
354  QList<int> plords; // ordinal numbers per placeholder occurrence
355  #ifndef NDEBUG
356  QVector<int> ords; // indicates which placeholders are present
357  #endif
358  int slen = trans.length();
359  int spos = 0;
360  int tpos = trans.indexOf(plchar);
361  while (tpos >= 0)
362  {
363  int ctpos = tpos;
364 
365  tpos++;
366  if (tpos == slen)
367  break;
368 
369  if (trans[tpos].digitValue() > 0) // %0 not considered a placeholder
370  {
371  // Get the placeholder ordinal.
372  int plord = 0;
373  while (tpos < slen && trans[tpos].digitValue() >= 0)
374  {
375  plord = 10 * plord + trans[tpos].digitValue();
376  tpos++;
377  }
378  plord--; // ordinals are zero based
379 
380  #ifndef NDEBUG
381  // Perhaps enlarge storage for indicators.
382  // Note that QVector<int> will initialize new elements to 0,
383  // as they are supposed to be.
384  if (plord >= ords.size())
385  ords.resize(plord + 1);
386 
387  // Indicate that placeholder with computed ordinal is present.
388  ords[plord] = 1;
389  #endif
390 
391  // Store text segment prior to placeholder and placeholder number.
392  tsegs.append(trans.mid(spos, ctpos - spos));
393  plords.append(plord);
394 
395  // Position of next text segment.
396  spos = tpos;
397  }
398 
399  tpos = trans.indexOf(plchar, tpos);
400  }
401  // Store last text segment.
402  tsegs.append(trans.mid(spos));
403 
404  #ifndef NDEBUG
405  // Perhaps enlarge storage for plural-number ordinal.
406  if (!plural.isEmpty() && numberOrd >= ords.size())
407  ords.resize(numberOrd + 1);
408 
409  // Message might have plural but without plural placeholder, which is an
410  // allowed state. To ease further logic, indicate that plural placeholder
411  // is present anyway if message has plural.
412  if (!plural.isEmpty())
413  ords[numberOrd] = 1;
414  #endif
415 
416  // Assemble the final string from text segments and arguments.
417  QString final;
418  for (int i = 0; i < plords.size(); i++)
419  {
420  final.append(tsegs.at(i));
421  if (plords.at(i) >= args.size())
422  // too little arguments
423  {
424  // put back the placeholder
425  final.append(QLatin1Char('%') + QString::number(plords.at(i) + 1));
426  #ifndef NDEBUG
427  if (!partial)
428  // spoof the message
429  final.append(QLatin1String("(I18N_ARGUMENT_MISSING)"));
430  #endif
431  }
432  else
433  // just fine
434  final.append(args.at(plords.at(i)));
435  }
436  final.append(tsegs.last());
437 
438  #ifndef NDEBUG
439  if (!partial)
440  {
441  // Check that there are no gaps in numbering sequence of placeholders.
442  bool gaps = false;
443  for (int i = 0; i < ords.size(); i++)
444  if (!ords.at(i))
445  {
446  gaps = true;
447  kDebug(173) << QString::fromLatin1("Placeholder %%1 skipped in message {%2}.")
448  .arg(QString::number(i + 1), shortenMessage(trans));
449  }
450  // If no gaps, check for mismatch between number of unique placeholders and
451  // actually supplied arguments.
452  if (!gaps && ords.size() != args.size())
453  kDebug(173) << QString::fromLatin1("%1 instead of %2 arguments to message {%3} supplied before conversion.")
454  .arg(args.size()).arg(ords.size()).arg(shortenMessage(trans));
455 
456  // Some spoofs.
457  if (gaps)
458  final.append(QLatin1String("(I18N_GAPS_IN_PLACEHOLDER_SEQUENCE)"));
459  if (ords.size() < args.size())
460  final.append(QLatin1String("(I18N_EXCESS_ARGUMENTS_SUPPLIED)"));
461  if (!plural.isEmpty() && !numberSet)
462  final.append(QLatin1String("(I18N_PLURAL_ARGUMENT_MISSING)"));
463  }
464  #endif
465 
466  return final;
467 }
468 
469 QString KLocalizedStringPrivate::postFormat (const QString &text,
470  const QString &lang,
471  const QString &ctxt) const
472 {
473  const KLocalizedStringPrivateStatics *s = staticsKLSP;
474  QMutexLocker lock(kLocaleMutex());
475 
476  QString final = text;
477 
478  // Transform any semantic markup into visual formatting.
479  if (s->formatters.contains(lang)) {
480  final = s->formatters[lang]->format(final, ctxt);
481  }
482 
483  return final;
484 }
485 
486 QString KLocalizedStringPrivate::substituteTranscript (const QString &strans,
487  const QString &lang,
488  const QString &ctry,
489  const QString &final,
490  bool &fallback) const
491 {
492  const KLocalizedStringPrivateStatics *s = staticsKLSP;
493  QMutexLocker lock(kLocaleMutex());
494 
495  if (s->ktrs == NULL)
496  // Scripting engine not available.
497  return QString();
498 
499  // Iterate by interpolations.
500  QString sfinal;
501  fallback = false;
502  int ppos = 0;
503  int tpos = strans.indexOf(s->startInterp);
504  while (tpos >= 0)
505  {
506  // Resolve substitutions in preceding text.
507  QString ptext = substituteSimple(strans.mid(ppos, tpos - ppos),
508  s->scriptPlchar, true);
509  sfinal.append(ptext);
510 
511  // Resolve interpolation.
512  QString result;
513  bool fallbackLocal;
514  tpos = resolveInterpolation(strans, tpos, lang, ctry, final,
515  result, fallbackLocal);
516 
517  // If there was a problem in parsing the interpolation, cannot proceed
518  // (debug info already reported while parsing).
519  if (tpos < 0) {
520  return QString();
521  }
522  // If fallback has been explicitly requested, indicate global fallback
523  // but proceed with evaluations (other interpolations may set states).
524  if (fallbackLocal) {
525  fallback = true;
526  }
527 
528  // Add evaluated interpolation to the text.
529  sfinal.append(result);
530 
531  // On to next interpolation.
532  ppos = tpos;
533  tpos = strans.indexOf(s->startInterp, tpos);
534  }
535  // Last text segment.
536  sfinal.append(substituteSimple(strans.mid(ppos), s->scriptPlchar, true));
537 
538  // Return empty string if fallback was requested.
539  return fallback ? QString() : sfinal;
540 }
541 
542 int KLocalizedStringPrivate::resolveInterpolation (const QString &strans,
543  int pos,
544  const QString &lang,
545  const QString &ctry,
546  const QString &final,
547  QString &result,
548  bool &fallback) const
549 {
550  // pos is the position of opening character sequence.
551  // Returns the position of first character after closing sequence,
552  // or -1 in case of parsing error.
553  // result is set to result of Transcript evaluation.
554  // fallback is set to true if Transcript evaluation requested so.
555 
556  KLocalizedStringPrivateStatics *s = staticsKLSP;
557  QMutexLocker lock(kLocaleMutex());
558 
559  result.clear();
560  fallback = false;
561 
562  // Split interpolation into arguments.
563  QList<QVariant> iargs;
564  int slen = strans.length();
565  int islen = s->startInterp.length();
566  int ielen = s->endInterp.length();
567  int tpos = pos + s->startInterp.length();
568  while (1)
569  {
570  // Skip whitespace.
571  while (tpos < slen && strans[tpos].isSpace()) {
572  ++tpos;
573  }
574  if (tpos == slen) {
575  kDebug(173) << QString::fromLatin1("Unclosed interpolation {%1} in message {%2}.")
576  .arg(strans.mid(pos, tpos - pos), shortenMessage(strans));
577  return -1;
578  }
579  if (strans.mid(tpos, ielen) == s->endInterp) {
580  break; // no more arguments
581  }
582 
583  // Parse argument: may be concatenated from free and quoted text,
584  // and sub-interpolations.
585  // Free and quoted segments may contain placeholders, substitute them;
586  // recurse into sub-interpolations.
587  // Free segments may be value references, parse and record for
588  // consideration at the end.
589  // Mind backslash escapes throughout.
590  QStringList segs;
591  QVariant vref;
592  while ( !strans[tpos].isSpace()
593  && strans.mid(tpos, ielen) != s->endInterp)
594  {
595  if (strans[tpos] == QLatin1Char('\'')) { // quoted segment
596  QString seg;
597  ++tpos; // skip opening quote
598  // Find closing quote.
599  while (tpos < slen && strans[tpos] != QLatin1Char('\'')) {
600  if (strans[tpos] == QLatin1Char('\\'))
601  ++tpos; // escape next character
602  seg.append(strans[tpos]);
603  ++tpos;
604  }
605  if (tpos == slen) {
606  kDebug(173) << QString::fromLatin1("Unclosed quote in interpolation {%1} in message {%2}.")
607  .arg(strans.mid(pos, tpos - pos), shortenMessage(strans));
608  return -1;
609  }
610 
611  // Append to list of segments, resolving placeholders.
612  segs.append(substituteSimple(seg, s->scriptPlchar, true));
613 
614  ++tpos; // skip closing quote
615  }
616  else if (strans.mid(tpos, islen) == s->startInterp) { // sub-interpolation
617  QString resultLocal;
618  bool fallbackLocal;
619  tpos = resolveInterpolation(strans, tpos, lang, ctry, final,
620  resultLocal, fallbackLocal);
621  if (tpos < 0) { // unrecoverable problem in sub-interpolation
622  // Error reported in the subcall.
623  return tpos;
624  }
625  if (fallbackLocal) { // sub-interpolation requested fallback
626  fallback = true;
627  }
628  segs.append(resultLocal);
629  }
630  else { // free segment
631  QString seg;
632  // Find whitespace, quote, opening or closing sequence.
633  while ( tpos < slen
634  && !strans[tpos].isSpace() && strans[tpos] != QLatin1Char('\'')
635  && strans.mid(tpos, islen) != s->startInterp
636  && strans.mid(tpos, ielen) != s->endInterp)
637  {
638  if (strans[tpos] == QLatin1Char('\\'))
639  ++tpos; // escape next character
640  seg.append(strans[tpos]);
641  ++tpos;
642  }
643  if (tpos == slen) {
644  kDebug(173) << QString::fromLatin1("Non-terminated interpolation {%1} in message {%2}.")
645  .arg(strans.mid(pos, tpos - pos), shortenMessage(strans));
646  return -1;
647  }
648 
649  // The free segment may look like a value reference;
650  // in that case, record which value it would reference,
651  // and add verbatim to the segment list.
652  // Otherwise, do a normal substitution on the segment.
653  vref = segmentToValue(seg);
654  if (vref.isValid()) {
655  segs.append(seg);
656  }
657  else {
658  segs.append(substituteSimple(seg, s->scriptPlchar, true));
659  }
660  }
661  }
662 
663  // Append this argument to rest of the arguments.
664  // If the there was a single text segment and it was a proper value
665  // reference, add it instead of the joined segments.
666  // Otherwise, add the joined segments.
667  if (segs.size() == 1 && vref.isValid()) {
668  iargs.append(vref);
669  }
670  else {
671  iargs.append(segs.join(QString()));
672  }
673  }
674  tpos += ielen; // skip to first character after closing sequence
675 
676  // NOTE: Why not substitute placeholders (via substituteSimple) in one
677  // global pass, then handle interpolations in second pass? Because then
678  // there is the danger of substituted text or sub-interpolations producing
679  // quotes and escapes themselves, which would mess up the parsing.
680 
681  // Evaluate interpolation.
682  QString msgctxt = QString::fromUtf8(ctxt);
683  QString msgid = QString::fromUtf8(msg);
684  QString scriptError;
685  bool fallbackLocal;
686  result = s->ktrs->eval(iargs, lang, ctry,
687  msgctxt, dynctxt, msgid,
688  args, vals, final, s->scriptModulesToLoad,
689  scriptError, fallbackLocal);
690  // s->scriptModulesToLoad will be cleared during the call.
691 
692  if (fallbackLocal) { // evaluation requested fallback
693  fallback = true;
694  }
695  if (!scriptError.isEmpty()) { // problem with evaluation
696  fallback = true; // also signal fallback
697  if (!scriptError.isEmpty()) {
698  kDebug(173) << QString::fromLatin1("Interpolation {%1} in {%2} failed: %3")
699  .arg(strans.mid(pos, tpos - pos), shortenMessage(strans), scriptError);
700  }
701  }
702 
703  return tpos;
704 }
705 
706 QVariant KLocalizedStringPrivate::segmentToValue (const QString &seg) const
707 {
708  const KLocalizedStringPrivateStatics *s = staticsKLSP;
709  QMutexLocker lock(kLocaleMutex());
710 
711  // Return invalid variant if segment is either not a proper
712  // value reference, or the reference is out of bounds.
713 
714  // Value reference must start with a special character.
715  if (seg.left(1) != s->scriptVachar) {
716  return QVariant();
717  }
718 
719  // Reference number must start with 1-9.
720  // (If numstr is empty, toInt() will return 0.)
721  QString numstr = seg.mid(1);
722  if (numstr.left(1).toInt() < 1) {
723  return QVariant();
724  }
725 
726  // Number must be valid and in bounds.
727  bool ok;
728  int index = numstr.toInt(&ok) - 1;
729  if (!ok || index >= vals.size()) {
730  return QVariant();
731  }
732 
733  // Passed all hoops.
734  return vals.at(index);
735 }
736 
737 QString KLocalizedStringPrivate::postTranscript (const QString &pcall,
738  const QString &lang,
739  const QString &ctry,
740  const QString &final) const
741 {
742  KLocalizedStringPrivateStatics *s = staticsKLSP;
743  QMutexLocker lock(kLocaleMutex());
744 
745  if (s->ktrs == NULL)
746  // Scripting engine not available.
747  // (Though this cannot happen, we wouldn't be here then.)
748  return QString();
749 
750  // Resolve the post call.
751  QList<QVariant> iargs;
752  iargs.append(pcall);
753  QString msgctxt = QString::fromUtf8(ctxt);
754  QString msgid = QString::fromUtf8(msg);
755  QString scriptError;
756  bool fallback;
757  QString dummy = s->ktrs->eval(iargs, lang, ctry,
758  msgctxt, dynctxt, msgid,
759  args, vals, final, s->scriptModulesToLoad,
760  scriptError, fallback);
761  // s->scriptModulesToLoad will be cleared during the call.
762 
763  // If the evaluation went wrong.
764  if (!scriptError.isEmpty())
765  {
766  kDebug(173) << QString::fromLatin1("Post call {%1} for message {%2} failed: %3")
767  .arg(pcall, shortenMessage(msgid), scriptError);
768  return QString();
769  }
770 
771  return final;
772 }
773 
774 static QString wrapNum (const QString &tag, const QString &numstr,
775  int fieldWidth, const QChar &fillChar)
776 {
777  QString optag;
778  if (fieldWidth != 0) {
779  QString fillString = KuitSemantics::escape(fillChar);
780  optag = QString::fromLatin1("<%1 width='%2' fill='%3'>")
781  .arg(tag, QString::number(fieldWidth), fillString);
782  } else {
783  optag = QString::fromLatin1("<%1>").arg(tag);
784  }
785  QString cltag = QString::fromLatin1("</%1>").arg(tag);
786  return optag + numstr + cltag;
787 }
788 
789 KLocalizedString KLocalizedString::subs (int a, int fieldWidth, int base,
790  const QChar &fillChar) const
791 {
792  KLocalizedString kls(*this);
793  if (!kls.d->plural.isEmpty() && !kls.d->numberSet) {
794  kls.d->number = static_cast<pluraln>(abs(a));
795  kls.d->numberSet = true;
796  kls.d->numberOrd = d->args.size();
797  }
798  kls.d->args.append(wrapNum(QString::fromLatin1(KUIT_NUMINTG), QString::number(a, base),
799  fieldWidth, fillChar));
800  kls.d->vals.append(static_cast<intn>(a));
801  return kls;
802 }
803 
804 KLocalizedString KLocalizedString::subs (uint a, int fieldWidth, int base,
805  const QChar &fillChar) const
806 {
807  KLocalizedString kls(*this);
808  if (!kls.d->plural.isEmpty() && !kls.d->numberSet) {
809  kls.d->number = static_cast<pluraln>(a);
810  kls.d->numberSet = true;
811  kls.d->numberOrd = d->args.size();
812  }
813  kls.d->args.append(wrapNum(QString::fromLatin1(KUIT_NUMINTG), QString::number(a, base),
814  fieldWidth, fillChar));
815  kls.d->vals.append(static_cast<uintn>(a));
816  return kls;
817 }
818 
819 KLocalizedString KLocalizedString::subs (long a, int fieldWidth, int base,
820  const QChar &fillChar) const
821 {
822  KLocalizedString kls(*this);
823  if (!kls.d->plural.isEmpty() && !kls.d->numberSet) {
824  kls.d->number = static_cast<pluraln>(abs(a));
825  kls.d->numberSet = true;
826  kls.d->numberOrd = d->args.size();
827  }
828  kls.d->args.append(wrapNum(QString::fromLatin1(KUIT_NUMINTG), QString::number(a, base),
829  fieldWidth, fillChar));
830  kls.d->vals.append(static_cast<intn>(a));
831  return kls;
832 }
833 
834 KLocalizedString KLocalizedString::subs (ulong a, int fieldWidth, int base,
835  const QChar &fillChar) const
836 {
837  KLocalizedString kls(*this);
838  if (!kls.d->plural.isEmpty() && !kls.d->numberSet) {
839  kls.d->number = static_cast<pluraln>(a);
840  kls.d->numberSet = true;
841  kls.d->numberOrd = d->args.size();
842  }
843  kls.d->args.append(wrapNum(QString::fromLatin1(KUIT_NUMINTG), QString::number(a, base),
844  fieldWidth, fillChar));
845  kls.d->vals.append(static_cast<uintn>(a));
846  return kls;
847 }
848 
849 KLocalizedString KLocalizedString::subs (qlonglong a, int fieldWidth, int base,
850  const QChar &fillChar) const
851 {
852  KLocalizedString kls(*this);
853  if (!kls.d->plural.isEmpty() && !kls.d->numberSet) {
854  kls.d->number = static_cast<pluraln>(qAbs(a));
855  kls.d->numberSet = true;
856  kls.d->numberOrd = d->args.size();
857  }
858  kls.d->args.append(wrapNum(QString::fromLatin1(KUIT_NUMINTG), QString::number(a, base),
859  fieldWidth, fillChar));
860  kls.d->vals.append(static_cast<intn>(a));
861  return kls;
862 }
863 
864 KLocalizedString KLocalizedString::subs (qulonglong a, int fieldWidth, int base,
865  const QChar &fillChar) const
866 {
867  KLocalizedString kls(*this);
868  if (!kls.d->plural.isEmpty() && !kls.d->numberSet) {
869  kls.d->number = static_cast<pluraln>(a);
870  kls.d->numberSet = true;
871  kls.d->numberOrd = d->args.size();
872  }
873  kls.d->args.append(wrapNum(QString::fromLatin1(KUIT_NUMINTG), QString::number(a, base),
874  fieldWidth, fillChar));
875  kls.d->vals.append(static_cast<uintn>(a));
876  return kls;
877 }
878 
879 KLocalizedString KLocalizedString::subs (double a, int fieldWidth,
880  char format, int precision,
881  const QChar &fillChar) const
882 {
883  KLocalizedString kls(*this);
884  kls.d->args.append(wrapNum(QString::fromLatin1(KUIT_NUMREAL),
885  QString::number(a, format, precision),
886  fieldWidth, fillChar));
887  kls.d->vals.append(static_cast<realn>(a));
888  return kls;
889 }
890 
891 KLocalizedString KLocalizedString::subs (QChar a, int fieldWidth,
892  const QChar &fillChar) const
893 {
894  KLocalizedString kls(*this);
895  kls.d->args.append(QString::fromLatin1("%1").arg(a, fieldWidth, fillChar));
896  kls.d->vals.append(QString(a));
897  return kls;
898 }
899 
900 KLocalizedString KLocalizedString::subs (const QString &a, int fieldWidth,
901  const QChar &fillChar) const
902 {
903  KLocalizedString kls(*this);
904  // if (!KuitSemantics::mightBeRichText(a)) { ...
905  // Do not try to auto-escape non-rich-text alike arguments;
906  // breaks compatibility with 4.0. Perhaps for KDE 5?
907  // Perhaps bad idea alltogether (too much surprise)?
908  kls.d->args.append(QString::fromLatin1("%1").arg(a, fieldWidth, fillChar));
909  kls.d->vals.append(a);
910  return kls;
911 }
912 
913 KLocalizedString KLocalizedString::inContext (const QString &key,
914  const QString &text) const
915 {
916  KLocalizedString kls(*this);
917  kls.d->dynctxt[key] = text;
918  return kls;
919 }
920 
921 KLocalizedString ki18n (const char* msg)
922 {
923  return KLocalizedString(NULL, msg, NULL);
924 }
925 
926 KLocalizedString ki18nc (const char* ctxt, const char *msg)
927 {
928  return KLocalizedString(ctxt, msg, NULL);
929 }
930 
931 KLocalizedString ki18np (const char* singular, const char* plural)
932 {
933  return KLocalizedString(NULL, singular, plural);
934 }
935 
936 KLocalizedString ki18ncp (const char* ctxt,
937  const char* singular, const char* plural)
938 {
939  return KLocalizedString(ctxt, singular, plural);
940 }
941 
942 extern "C"
943 {
944  typedef KTranscript *(*InitFunc)();
945 }
946 
947 void KLocalizedStringPrivate::loadTranscript ()
948 {
949  KLocalizedStringPrivateStatics *s = staticsKLSP;
950  QMutexLocker lock(kLocaleMutex());
951 
952  s->loadTranscriptCalled = true;
953  s->ktrs = NULL; // null indicates that Transcript is not available
954 
955  KLibrary lib(QLatin1String("ktranscript"));
956  if (!lib.load()) {
957  kDebug(173) << "Cannot load transcript plugin:" << lib.errorString();
958  return;
959  }
960 
961  InitFunc initf = (InitFunc) lib.resolveFunction("load_transcript");
962  if (!initf) {
963  lib.unload();
964  kDebug(173) << "Cannot find function load_transcript in transcript plugin.";
965  return;
966  }
967 
968  s->ktrs = initf();
969 }
970 
971 void KLocalizedString::notifyCatalogsUpdated (const QStringList &languages,
972  const QList<KCatalogName> &catalogs)
973 {
974  KLocalizedStringPrivate::notifyCatalogsUpdated(languages, catalogs);
975 }
976 
977 void KLocalizedStringPrivate::notifyCatalogsUpdated (const QStringList &languages,
978  const QList<KCatalogName> &catalogs)
979 {
980  if (staticsKLSP.isDestroyed()) {
981  return;
982  }
983  KLocalizedStringPrivateStatics *s = staticsKLSP;
984  // Very important: do not the mutex here.
985  //QMutexLocker lock(kLocaleMutex());
986 
987  // Find script modules for all included language/catalogs that have them,
988  // and remember their paths.
989  // A more specific module may reference the calls from a less specific,
990  // and the catalog list is ordered from more to less specific. Therefore,
991  // work on reversed list of catalogs.
992  foreach (const QString &lang, languages) {
993  for (int i = catalogs.size() - 1; i >= 0; --i) {
994  const KCatalogName &cat(catalogs[i]);
995 
996  // Assemble module's relative path.
997  QString modrpath = lang + QLatin1Char('/') + s->scriptDir + QLatin1Char('/')
998  + cat.name + QLatin1Char('/') + cat.name + QLatin1String(".js");
999 
1000  // Try to find this module.
1001  QString modapath = KStandardDirs::locate("locale", modrpath);
1002 
1003  // If the module exists and hasn't been already included.
1004  if ( !modapath.isEmpty()
1005  && !s->scriptModules[lang].contains(cat.name))
1006  {
1007  // Indicate that the module has been considered.
1008  s->scriptModules[lang].append(cat.name);
1009 
1010  // Store the absolute path and language of the module,
1011  // to load on next script evaluation.
1012  QStringList mod;
1013  mod.append(modapath);
1014  mod.append(lang);
1015  s->scriptModulesToLoad.append(mod);
1016  }
1017  }
1018  }
1019 
1020  // Create visual formatters for each new language.
1021  foreach (const QString &lang, languages) {
1022  if (!s->formatters.contains(lang)) {
1023  s->formatters.insert(lang, new KuitSemantics(lang));
1024  }
1025  }
1026 }
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Fri Dec 7 2012 15:57:20 by doxygen 1.8.1 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDECore

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

kdelibs-4.8.5 API Reference

Skip menu "kdelibs-4.8.5 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal