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

KDECore

  • sources
  • kde-4.14
  • kdelibs
  • 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(), NULL);
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, NULL);
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  QByteArray catname;
239  if (catalogName != NULL) {
240  catname = catalogName->toUtf8();
241  }
242  if (locale != NULL) {
243  if (!ctxt.isEmpty() && !plural.isEmpty()) {
244  locale->translateRawFrom(catname, ctxt, msg, plural, number,
245  &lang, &rawtrans);
246  } else if (!plural.isEmpty()) {
247  locale->translateRawFrom(catname, msg, plural, number,
248  &lang, &rawtrans);
249  } else if (!ctxt.isEmpty()) {
250  locale->translateRawFrom(catname, ctxt, msg,
251  &lang, &rawtrans);
252  } else {
253  locale->translateRawFrom(catname, msg,
254  &lang, &rawtrans);
255  }
256  ctry = locale->country();
257  } else {
258  lang = KLocale::defaultLanguage();
259  ctry = QLatin1Char('C');
260  rawtrans = selectForEnglish();
261  }
262 
263  // Set ordinary translation and possibly scripted translation.
264  QString trans, strans;
265  int cdpos = rawtrans.indexOf(s->theFence);
266  if (cdpos > 0)
267  {
268  // Script fence has been found, strip the scripted from the
269  // ordinary translation.
270  trans = rawtrans.left(cdpos);
271 
272  // Scripted translation.
273  strans = rawtrans.mid(cdpos + s->theFence.length());
274 
275  // Try to initialize Transcript if not initialized, and script not empty.
276  if ( !s->loadTranscriptCalled && !strans.isEmpty()
277  && locale && locale->useTranscript())
278  {
279  if (KGlobal::hasMainComponent())
280  loadTranscript();
281  else
282  kDebug(173) << QString::fromLatin1("Scripted message {%1} before transcript engine can be loaded.")
283  .arg(shortenMessage(trans));
284  }
285  }
286  else if (cdpos < 0)
287  {
288  // No script fence, use translation as is.
289  trans = rawtrans;
290  }
291  else // cdpos == 0
292  {
293  // The msgstr starts with the script fence, no ordinary translation.
294  // This is not allowed, consider message not translated.
295  kDebug(173) << QString::fromLatin1("Scripted message {%1} without ordinary translation, discarded.")
296  .arg(shortenMessage(trans)) ;
297  trans = selectForEnglish();
298  }
299 
300  // Substitute placeholders in ordinary translation.
301  QString final = substituteSimple(trans);
302  // Post-format ordinary translation.
303  final = postFormat(final, lang, QString::fromLatin1(ctxt));
304 
305  // If there is also a scripted translation.
306  if (!strans.isEmpty()) {
307  // Evaluate scripted translation.
308  bool fallback;
309  QString sfinal = substituteTranscript(strans, lang, ctry, final, fallback);
310 
311  // If any translation produced and no fallback requested.
312  if (!sfinal.isEmpty() && !fallback) {
313  final = postFormat(sfinal, lang, QString::fromLatin1(ctxt));
314  }
315  }
316 
317  // Execute any scripted post calls; they cannot modify the final result,
318  // but are used to set states.
319  if (s->ktrs != NULL)
320  {
321  QStringList pcalls = s->ktrs->postCalls(lang);
322  foreach(const QString &pcall, pcalls)
323  postTranscript(pcall, lang, ctry, final);
324  }
325 
326  return final;
327 }
328 
329 QString KLocalizedStringPrivate::selectForEnglish () const
330 {
331  QString trans;
332 
333  if (!plural.isEmpty()) {
334  if (number == 1) {
335  trans = QString::fromUtf8(msg);
336  }
337  else {
338  trans = QString::fromUtf8(plural);
339  }
340  }
341  else {
342  trans = QString::fromUtf8(msg);
343  }
344 
345  return trans;
346 }
347 
348 QString KLocalizedStringPrivate::substituteSimple (const QString &trans,
349  const QChar &plchar,
350  bool partial) const
351 {
352  #ifdef NDEBUG
353  Q_UNUSED(partial);
354  #endif
355 
356  QStringList tsegs; // text segments per placeholder occurrence
357  QList<int> plords; // ordinal numbers per placeholder occurrence
358  #ifndef NDEBUG
359  QVector<int> ords; // indicates which placeholders are present
360  #endif
361  int slen = trans.length();
362  int spos = 0;
363  int tpos = trans.indexOf(plchar);
364  while (tpos >= 0)
365  {
366  int ctpos = tpos;
367 
368  tpos++;
369  if (tpos == slen)
370  break;
371 
372  if (trans[tpos].digitValue() > 0) // %0 not considered a placeholder
373  {
374  // Get the placeholder ordinal.
375  int plord = 0;
376  while (tpos < slen && trans[tpos].digitValue() >= 0)
377  {
378  plord = 10 * plord + trans[tpos].digitValue();
379  tpos++;
380  }
381  plord--; // ordinals are zero based
382 
383  #ifndef NDEBUG
384  // Perhaps enlarge storage for indicators.
385  // Note that QVector<int> will initialize new elements to 0,
386  // as they are supposed to be.
387  if (plord >= ords.size())
388  ords.resize(plord + 1);
389 
390  // Indicate that placeholder with computed ordinal is present.
391  ords[plord] = 1;
392  #endif
393 
394  // Store text segment prior to placeholder and placeholder number.
395  tsegs.append(trans.mid(spos, ctpos - spos));
396  plords.append(plord);
397 
398  // Position of next text segment.
399  spos = tpos;
400  }
401 
402  tpos = trans.indexOf(plchar, tpos);
403  }
404  // Store last text segment.
405  tsegs.append(trans.mid(spos));
406 
407  #ifndef NDEBUG
408  // Perhaps enlarge storage for plural-number ordinal.
409  if (!plural.isEmpty() && numberOrd >= ords.size())
410  ords.resize(numberOrd + 1);
411 
412  // Message might have plural but without plural placeholder, which is an
413  // allowed state. To ease further logic, indicate that plural placeholder
414  // is present anyway if message has plural.
415  if (!plural.isEmpty())
416  ords[numberOrd] = 1;
417  #endif
418 
419  // Assemble the final string from text segments and arguments.
420  QString final;
421  for (int i = 0; i < plords.size(); i++)
422  {
423  final.append(tsegs.at(i));
424  if (plords.at(i) >= args.size())
425  // too little arguments
426  {
427  // put back the placeholder
428  final.append(QLatin1Char('%') + QString::number(plords.at(i) + 1));
429  #ifndef NDEBUG
430  if (!partial)
431  // spoof the message
432  final.append(QLatin1String("(I18N_ARGUMENT_MISSING)"));
433  #endif
434  }
435  else
436  // just fine
437  final.append(args.at(plords.at(i)));
438  }
439  final.append(tsegs.last());
440 
441  #ifndef NDEBUG
442  if (!partial)
443  {
444  // Check that there are no gaps in numbering sequence of placeholders.
445  bool gaps = false;
446  for (int i = 0; i < ords.size(); i++)
447  if (!ords.at(i))
448  {
449  gaps = true;
450  kDebug(173) << QString::fromLatin1("Placeholder %%1 skipped in message {%2}.")
451  .arg(QString::number(i + 1), shortenMessage(trans));
452  }
453  // If no gaps, check for mismatch between number of unique placeholders and
454  // actually supplied arguments.
455  if (!gaps && ords.size() != args.size())
456  kDebug(173) << QString::fromLatin1("%1 instead of %2 arguments to message {%3} supplied before conversion.")
457  .arg(args.size()).arg(ords.size()).arg(shortenMessage(trans));
458 
459  // Some spoofs.
460  if (gaps)
461  final.append(QLatin1String("(I18N_GAPS_IN_PLACEHOLDER_SEQUENCE)"));
462  if (ords.size() < args.size())
463  final.append(QLatin1String("(I18N_EXCESS_ARGUMENTS_SUPPLIED)"));
464  if (!plural.isEmpty() && !numberSet)
465  final.append(QLatin1String("(I18N_PLURAL_ARGUMENT_MISSING)"));
466  }
467  #endif
468 
469  return final;
470 }
471 
472 QString KLocalizedStringPrivate::postFormat (const QString &text,
473  const QString &lang,
474  const QString &ctxt) const
475 {
476  const KLocalizedStringPrivateStatics *s = staticsKLSP;
477  QMutexLocker lock(kLocaleMutex());
478 
479  QString final = text;
480 
481  // Transform any semantic markup into visual formatting.
482  if (s->formatters.contains(lang)) {
483  final = s->formatters[lang]->format(final, ctxt);
484  }
485 
486  return final;
487 }
488 
489 QString KLocalizedStringPrivate::substituteTranscript (const QString &strans,
490  const QString &lang,
491  const QString &ctry,
492  const QString &final,
493  bool &fallback) const
494 {
495  const KLocalizedStringPrivateStatics *s = staticsKLSP;
496  QMutexLocker lock(kLocaleMutex());
497 
498  if (s->ktrs == NULL)
499  // Scripting engine not available.
500  return QString();
501 
502  // Iterate by interpolations.
503  QString sfinal;
504  fallback = false;
505  int ppos = 0;
506  int tpos = strans.indexOf(s->startInterp);
507  while (tpos >= 0)
508  {
509  // Resolve substitutions in preceding text.
510  QString ptext = substituteSimple(strans.mid(ppos, tpos - ppos),
511  s->scriptPlchar, true);
512  sfinal.append(ptext);
513 
514  // Resolve interpolation.
515  QString result;
516  bool fallbackLocal;
517  tpos = resolveInterpolation(strans, tpos, lang, ctry, final,
518  result, fallbackLocal);
519 
520  // If there was a problem in parsing the interpolation, cannot proceed
521  // (debug info already reported while parsing).
522  if (tpos < 0) {
523  return QString();
524  }
525  // If fallback has been explicitly requested, indicate global fallback
526  // but proceed with evaluations (other interpolations may set states).
527  if (fallbackLocal) {
528  fallback = true;
529  }
530 
531  // Add evaluated interpolation to the text.
532  sfinal.append(result);
533 
534  // On to next interpolation.
535  ppos = tpos;
536  tpos = strans.indexOf(s->startInterp, tpos);
537  }
538  // Last text segment.
539  sfinal.append(substituteSimple(strans.mid(ppos), s->scriptPlchar, true));
540 
541  // Return empty string if fallback was requested.
542  return fallback ? QString() : sfinal;
543 }
544 
545 int KLocalizedStringPrivate::resolveInterpolation (const QString &strans,
546  int pos,
547  const QString &lang,
548  const QString &ctry,
549  const QString &final,
550  QString &result,
551  bool &fallback) const
552 {
553  // pos is the position of opening character sequence.
554  // Returns the position of first character after closing sequence,
555  // or -1 in case of parsing error.
556  // result is set to result of Transcript evaluation.
557  // fallback is set to true if Transcript evaluation requested so.
558 
559  KLocalizedStringPrivateStatics *s = staticsKLSP;
560  QMutexLocker lock(kLocaleMutex());
561 
562  result.clear();
563  fallback = false;
564 
565  // Split interpolation into arguments.
566  QList<QVariant> iargs;
567  int slen = strans.length();
568  int islen = s->startInterp.length();
569  int ielen = s->endInterp.length();
570  int tpos = pos + s->startInterp.length();
571  while (1)
572  {
573  // Skip whitespace.
574  while (tpos < slen && strans[tpos].isSpace()) {
575  ++tpos;
576  }
577  if (tpos == slen) {
578  kDebug(173) << QString::fromLatin1("Unclosed interpolation {%1} in message {%2}.")
579  .arg(strans.mid(pos, tpos - pos), shortenMessage(strans));
580  return -1;
581  }
582  if (strans.mid(tpos, ielen) == s->endInterp) {
583  break; // no more arguments
584  }
585 
586  // Parse argument: may be concatenated from free and quoted text,
587  // and sub-interpolations.
588  // Free and quoted segments may contain placeholders, substitute them;
589  // recurse into sub-interpolations.
590  // Free segments may be value references, parse and record for
591  // consideration at the end.
592  // Mind backslash escapes throughout.
593  QStringList segs;
594  QVariant vref;
595  while ( !strans[tpos].isSpace()
596  && strans.mid(tpos, ielen) != s->endInterp)
597  {
598  if (strans[tpos] == QLatin1Char('\'')) { // quoted segment
599  QString seg;
600  ++tpos; // skip opening quote
601  // Find closing quote.
602  while (tpos < slen && strans[tpos] != QLatin1Char('\'')) {
603  if (strans[tpos] == QLatin1Char('\\'))
604  ++tpos; // escape next character
605  seg.append(strans[tpos]);
606  ++tpos;
607  }
608  if (tpos == slen) {
609  kDebug(173) << QString::fromLatin1("Unclosed quote in interpolation {%1} in message {%2}.")
610  .arg(strans.mid(pos, tpos - pos), shortenMessage(strans));
611  return -1;
612  }
613 
614  // Append to list of segments, resolving placeholders.
615  segs.append(substituteSimple(seg, s->scriptPlchar, true));
616 
617  ++tpos; // skip closing quote
618  }
619  else if (strans.mid(tpos, islen) == s->startInterp) { // sub-interpolation
620  QString resultLocal;
621  bool fallbackLocal;
622  tpos = resolveInterpolation(strans, tpos, lang, ctry, final,
623  resultLocal, fallbackLocal);
624  if (tpos < 0) { // unrecoverable problem in sub-interpolation
625  // Error reported in the subcall.
626  return tpos;
627  }
628  if (fallbackLocal) { // sub-interpolation requested fallback
629  fallback = true;
630  }
631  segs.append(resultLocal);
632  }
633  else { // free segment
634  QString seg;
635  // Find whitespace, quote, opening or closing sequence.
636  while ( tpos < slen
637  && !strans[tpos].isSpace() && strans[tpos] != QLatin1Char('\'')
638  && strans.mid(tpos, islen) != s->startInterp
639  && strans.mid(tpos, ielen) != s->endInterp)
640  {
641  if (strans[tpos] == QLatin1Char('\\'))
642  ++tpos; // escape next character
643  seg.append(strans[tpos]);
644  ++tpos;
645  }
646  if (tpos == slen) {
647  kDebug(173) << QString::fromLatin1("Non-terminated interpolation {%1} in message {%2}.")
648  .arg(strans.mid(pos, tpos - pos), shortenMessage(strans));
649  return -1;
650  }
651 
652  // The free segment may look like a value reference;
653  // in that case, record which value it would reference,
654  // and add verbatim to the segment list.
655  // Otherwise, do a normal substitution on the segment.
656  vref = segmentToValue(seg);
657  if (vref.isValid()) {
658  segs.append(seg);
659  }
660  else {
661  segs.append(substituteSimple(seg, s->scriptPlchar, true));
662  }
663  }
664  }
665 
666  // Append this argument to rest of the arguments.
667  // If the there was a single text segment and it was a proper value
668  // reference, add it instead of the joined segments.
669  // Otherwise, add the joined segments.
670  if (segs.size() == 1 && vref.isValid()) {
671  iargs.append(vref);
672  }
673  else {
674  iargs.append(segs.join(QString()));
675  }
676  }
677  tpos += ielen; // skip to first character after closing sequence
678 
679  // NOTE: Why not substitute placeholders (via substituteSimple) in one
680  // global pass, then handle interpolations in second pass? Because then
681  // there is the danger of substituted text or sub-interpolations producing
682  // quotes and escapes themselves, which would mess up the parsing.
683 
684  // Evaluate interpolation.
685  QString msgctxt = QString::fromUtf8(ctxt);
686  QString msgid = QString::fromUtf8(msg);
687  QString scriptError;
688  bool fallbackLocal;
689  result = s->ktrs->eval(iargs, lang, ctry,
690  msgctxt, dynctxt, msgid,
691  args, vals, final, s->scriptModulesToLoad,
692  scriptError, fallbackLocal);
693  // s->scriptModulesToLoad will be cleared during the call.
694 
695  if (fallbackLocal) { // evaluation requested fallback
696  fallback = true;
697  }
698  if (!scriptError.isEmpty()) { // problem with evaluation
699  fallback = true; // also signal fallback
700  if (!scriptError.isEmpty()) {
701  kDebug(173) << QString::fromLatin1("Interpolation {%1} in {%2} failed: %3")
702  .arg(strans.mid(pos, tpos - pos), shortenMessage(strans), scriptError);
703  }
704  }
705 
706  return tpos;
707 }
708 
709 QVariant KLocalizedStringPrivate::segmentToValue (const QString &seg) const
710 {
711  const KLocalizedStringPrivateStatics *s = staticsKLSP;
712  QMutexLocker lock(kLocaleMutex());
713 
714  // Return invalid variant if segment is either not a proper
715  // value reference, or the reference is out of bounds.
716 
717  // Value reference must start with a special character.
718  if (seg.left(1) != s->scriptVachar) {
719  return QVariant();
720  }
721 
722  // Reference number must start with 1-9.
723  // (If numstr is empty, toInt() will return 0.)
724  QString numstr = seg.mid(1);
725  if (numstr.left(1).toInt() < 1) {
726  return QVariant();
727  }
728 
729  // Number must be valid and in bounds.
730  bool ok;
731  int index = numstr.toInt(&ok) - 1;
732  if (!ok || index >= vals.size()) {
733  return QVariant();
734  }
735 
736  // Passed all hoops.
737  return vals.at(index);
738 }
739 
740 QString KLocalizedStringPrivate::postTranscript (const QString &pcall,
741  const QString &lang,
742  const QString &ctry,
743  const QString &final) const
744 {
745  KLocalizedStringPrivateStatics *s = staticsKLSP;
746  QMutexLocker lock(kLocaleMutex());
747 
748  if (s->ktrs == NULL)
749  // Scripting engine not available.
750  // (Though this cannot happen, we wouldn't be here then.)
751  return QString();
752 
753  // Resolve the post call.
754  QList<QVariant> iargs;
755  iargs.append(pcall);
756  QString msgctxt = QString::fromUtf8(ctxt);
757  QString msgid = QString::fromUtf8(msg);
758  QString scriptError;
759  bool fallback;
760  QString dummy = s->ktrs->eval(iargs, lang, ctry,
761  msgctxt, dynctxt, msgid,
762  args, vals, final, s->scriptModulesToLoad,
763  scriptError, fallback);
764  // s->scriptModulesToLoad will be cleared during the call.
765 
766  // If the evaluation went wrong.
767  if (!scriptError.isEmpty())
768  {
769  kDebug(173) << QString::fromLatin1("Post call {%1} for message {%2} failed: %3")
770  .arg(pcall, shortenMessage(msgid), scriptError);
771  return QString();
772  }
773 
774  return final;
775 }
776 
777 static QString wrapNum (const QString &tag, const QString &numstr,
778  int fieldWidth, const QChar &fillChar)
779 {
780  QString optag;
781  if (fieldWidth != 0) {
782  QString fillString = KuitSemantics::escape(fillChar);
783  optag = QString::fromLatin1("<%1 width='%2' fill='%3'>")
784  .arg(tag, QString::number(fieldWidth), fillString);
785  } else {
786  optag = QString::fromLatin1("<%1>").arg(tag);
787  }
788  QString cltag = QString::fromLatin1("</%1>").arg(tag);
789  return optag + numstr + cltag;
790 }
791 
792 KLocalizedString KLocalizedString::subs (int a, int fieldWidth, int base,
793  const QChar &fillChar) const
794 {
795  KLocalizedString kls(*this);
796  if (!kls.d->plural.isEmpty() && !kls.d->numberSet) {
797  kls.d->number = static_cast<pluraln>(abs(a));
798  kls.d->numberSet = true;
799  kls.d->numberOrd = d->args.size();
800  }
801  kls.d->args.append(wrapNum(QString::fromLatin1(KUIT_NUMINTG), QString::number(a, base),
802  fieldWidth, fillChar));
803  kls.d->vals.append(static_cast<intn>(a));
804  return kls;
805 }
806 
807 KLocalizedString KLocalizedString::subs (uint a, int fieldWidth, int base,
808  const QChar &fillChar) const
809 {
810  KLocalizedString kls(*this);
811  if (!kls.d->plural.isEmpty() && !kls.d->numberSet) {
812  kls.d->number = static_cast<pluraln>(a);
813  kls.d->numberSet = true;
814  kls.d->numberOrd = d->args.size();
815  }
816  kls.d->args.append(wrapNum(QString::fromLatin1(KUIT_NUMINTG), QString::number(a, base),
817  fieldWidth, fillChar));
818  kls.d->vals.append(static_cast<uintn>(a));
819  return kls;
820 }
821 
822 KLocalizedString KLocalizedString::subs (long a, int fieldWidth, int base,
823  const QChar &fillChar) const
824 {
825  KLocalizedString kls(*this);
826  if (!kls.d->plural.isEmpty() && !kls.d->numberSet) {
827  kls.d->number = static_cast<pluraln>(abs(a));
828  kls.d->numberSet = true;
829  kls.d->numberOrd = d->args.size();
830  }
831  kls.d->args.append(wrapNum(QString::fromLatin1(KUIT_NUMINTG), QString::number(a, base),
832  fieldWidth, fillChar));
833  kls.d->vals.append(static_cast<intn>(a));
834  return kls;
835 }
836 
837 KLocalizedString KLocalizedString::subs (ulong a, int fieldWidth, int base,
838  const QChar &fillChar) const
839 {
840  KLocalizedString kls(*this);
841  if (!kls.d->plural.isEmpty() && !kls.d->numberSet) {
842  kls.d->number = static_cast<pluraln>(a);
843  kls.d->numberSet = true;
844  kls.d->numberOrd = d->args.size();
845  }
846  kls.d->args.append(wrapNum(QString::fromLatin1(KUIT_NUMINTG), QString::number(a, base),
847  fieldWidth, fillChar));
848  kls.d->vals.append(static_cast<uintn>(a));
849  return kls;
850 }
851 
852 KLocalizedString KLocalizedString::subs (qlonglong a, int fieldWidth, int base,
853  const QChar &fillChar) const
854 {
855  KLocalizedString kls(*this);
856  if (!kls.d->plural.isEmpty() && !kls.d->numberSet) {
857  kls.d->number = static_cast<pluraln>(qAbs(a));
858  kls.d->numberSet = true;
859  kls.d->numberOrd = d->args.size();
860  }
861  kls.d->args.append(wrapNum(QString::fromLatin1(KUIT_NUMINTG), QString::number(a, base),
862  fieldWidth, fillChar));
863  kls.d->vals.append(static_cast<intn>(a));
864  return kls;
865 }
866 
867 KLocalizedString KLocalizedString::subs (qulonglong a, int fieldWidth, int base,
868  const QChar &fillChar) const
869 {
870  KLocalizedString kls(*this);
871  if (!kls.d->plural.isEmpty() && !kls.d->numberSet) {
872  kls.d->number = static_cast<pluraln>(a);
873  kls.d->numberSet = true;
874  kls.d->numberOrd = d->args.size();
875  }
876  kls.d->args.append(wrapNum(QString::fromLatin1(KUIT_NUMINTG), QString::number(a, base),
877  fieldWidth, fillChar));
878  kls.d->vals.append(static_cast<uintn>(a));
879  return kls;
880 }
881 
882 KLocalizedString KLocalizedString::subs (double a, int fieldWidth,
883  char format, int precision,
884  const QChar &fillChar) const
885 {
886  KLocalizedString kls(*this);
887  kls.d->args.append(wrapNum(QString::fromLatin1(KUIT_NUMREAL),
888  QString::number(a, format, precision),
889  fieldWidth, fillChar));
890  kls.d->vals.append(static_cast<realn>(a));
891  return kls;
892 }
893 
894 KLocalizedString KLocalizedString::subs (QChar a, int fieldWidth,
895  const QChar &fillChar) const
896 {
897  KLocalizedString kls(*this);
898  kls.d->args.append(QString::fromLatin1("%1").arg(a, fieldWidth, fillChar));
899  kls.d->vals.append(QString(a));
900  return kls;
901 }
902 
903 KLocalizedString KLocalizedString::subs (const QString &a, int fieldWidth,
904  const QChar &fillChar) const
905 {
906  KLocalizedString kls(*this);
907  // if (!KuitSemantics::mightBeRichText(a)) { ...
908  // Do not try to auto-escape non-rich-text alike arguments;
909  // breaks compatibility with 4.0. Perhaps for KDE 5?
910  // Perhaps bad idea alltogether (too much surprise)?
911  kls.d->args.append(QString::fromLatin1("%1").arg(a, fieldWidth, fillChar));
912  kls.d->vals.append(a);
913  return kls;
914 }
915 
916 KLocalizedString KLocalizedString::inContext (const QString &key,
917  const QString &text) const
918 {
919  KLocalizedString kls(*this);
920  kls.d->dynctxt[key] = text;
921  return kls;
922 }
923 
924 KLocalizedString ki18n (const char* msg)
925 {
926  return KLocalizedString(NULL, msg, NULL);
927 }
928 
929 KLocalizedString ki18nc (const char* ctxt, const char *msg)
930 {
931  return KLocalizedString(ctxt, msg, NULL);
932 }
933 
934 KLocalizedString ki18np (const char* singular, const char* plural)
935 {
936  return KLocalizedString(NULL, singular, plural);
937 }
938 
939 KLocalizedString ki18ncp (const char* ctxt,
940  const char* singular, const char* plural)
941 {
942  return KLocalizedString(ctxt, singular, plural);
943 }
944 
945 extern "C"
946 {
947  typedef KTranscript *(*InitFunc)();
948 }
949 
950 void KLocalizedStringPrivate::loadTranscript ()
951 {
952  KLocalizedStringPrivateStatics *s = staticsKLSP;
953  QMutexLocker lock(kLocaleMutex());
954 
955  s->loadTranscriptCalled = true;
956  s->ktrs = NULL; // null indicates that Transcript is not available
957 
958  KLibrary lib(QLatin1String("ktranscript"));
959  if (!lib.load()) {
960  kDebug(173) << "Cannot load transcript plugin:" << lib.errorString();
961  return;
962  }
963 
964  InitFunc initf = (InitFunc) lib.resolveFunction("load_transcript");
965  if (!initf) {
966  lib.unload();
967  kDebug(173) << "Cannot find function load_transcript in transcript plugin.";
968  return;
969  }
970 
971  s->ktrs = initf();
972 }
973 
974 void KLocalizedString::notifyCatalogsUpdated (const QStringList &languages,
975  const QList<KCatalogName> &catalogs)
976 {
977  KLocalizedStringPrivate::notifyCatalogsUpdated(languages, catalogs);
978 }
979 
980 void KLocalizedStringPrivate::notifyCatalogsUpdated (const QStringList &languages,
981  const QList<KCatalogName> &catalogs)
982 {
983  if (staticsKLSP.isDestroyed()) {
984  return;
985  }
986  KLocalizedStringPrivateStatics *s = staticsKLSP;
987  // Very important: do not the mutex here.
988  //QMutexLocker lock(kLocaleMutex());
989 
990  // Find script modules for all included language/catalogs that have them,
991  // and remember their paths.
992  // A more specific module may reference the calls from a less specific,
993  // and the catalog list is ordered from more to less specific. Therefore,
994  // work on reversed list of catalogs.
995  foreach (const QString &lang, languages) {
996  for (int i = catalogs.size() - 1; i >= 0; --i) {
997  const KCatalogName &cat(catalogs[i]);
998 
999  // Assemble module's relative path.
1000  QString modrpath = lang + QLatin1Char('/') + s->scriptDir + QLatin1Char('/')
1001  + cat.name + QLatin1Char('/') + cat.name + QLatin1String(".js");
1002 
1003  // Try to find this module.
1004  QString modapath = KStandardDirs::locate("locale", modrpath);
1005 
1006  // If the module exists and hasn't been already included.
1007  if ( !modapath.isEmpty()
1008  && !s->scriptModules[lang].contains(cat.name))
1009  {
1010  // Indicate that the module has been considered.
1011  s->scriptModules[lang].append(cat.name);
1012 
1013  // Store the absolute path and language of the module,
1014  // to load on next script evaluation.
1015  QStringList mod;
1016  mod.append(modapath);
1017  mod.append(lang);
1018  s->scriptModulesToLoad.append(mod);
1019  }
1020  }
1021  }
1022 
1023  // Create visual formatters for each new language.
1024  foreach (const QString &lang, languages) {
1025  if (!s->formatters.contains(lang)) {
1026  s->formatters.insert(lang, new KuitSemantics(lang));
1027  }
1028  }
1029 }
QString::indexOf
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
QString::append
QString & append(QChar ch)
KLocalizedString::notifyCatalogsUpdated
static void notifyCatalogsUpdated(const QStringList &languages, const QList< KCatalogName > &catalogs)
Definition: klocalizedstring.cpp:974
KLocalizedString::toString
QString toString() const
Finalizes the translation, creates QString with placeholders substituted.
Definition: klocalizedstring.cpp:192
kdebug.h
KUIT_NUMREAL
#define KUIT_NUMREAL
Definition: kuitsemantics_p.h:88
QByteArray
kuitsemantics_p.h
KuitSemantics::escape
static QString escape(const QString &text)
Convert &, ", ', <, > characters into XML entities &, <, >, ', ", respectively.
Definition: kuitsemantics.cpp:1633
InitFunc
KTranscript *(* InitFunc)()
Definition: klocalizedstring.cpp:947
ki18n
KLocalizedString ki18n(const char *msg)
Creates localized string from a given message.
Definition: klocalizedstring.cpp:924
QChar
K_GLOBAL_STATIC
#define K_GLOBAL_STATIC(TYPE, NAME)
This macro makes it easy to use non-POD types as global statics.
Definition: kglobal.h:221
KStandardDirs::locate
static QString locate(const char *type, const QString &filename, const KComponentData &cData=KGlobal::mainComponent())
This function is just for convenience.
Definition: kstandarddirs.cpp:2085
QList::at
const T & at(int i) const
KuitSemantics
class for formatting semantic markup in UI messages
Definition: kuitsemantics_p.h:38
klocale_p.h
shortenMessage
static QString shortenMessage(const QString &str)
Definition: klocalizedstring.cpp:43
KLocalizedString::~KLocalizedString
~KLocalizedString()
Destructor.
Definition: klocalizedstring.cpp:182
KCatalogName
Definition: kcatalogname_p.h:25
QStringList::join
QString join(const QString &separator) const
KLocalizedString::inContext
KLocalizedString inContext(const QString &key, const QString &text) const
Adds dynamic context to the message.
Definition: klocalizedstring.cpp:916
KLocale::useTranscript
bool useTranscript() const
Reports whether evaluation of translation scripts is enabled.
Definition: klocale.cpp:630
klocale.h
ki18np
KLocalizedString ki18np(const char *singular, const char *plural)
Creates localized string from a given plural and singular form.
Definition: klocalizedstring.cpp:934
QList::size
int size() const
QString::clear
void clear()
KLocalizedString::isEmpty
bool isEmpty() const
Checks whether the message is empty.
Definition: klocalizedstring.cpp:187
kglobal.h
QString::number
QString number(int n, int base)
QList::append
void append(const T &value)
QString::fromUtf8
QString fromUtf8(const char *str, int size)
QVector::resize
void resize(int size)
QHash< QString, QString >
KUIT_NUMINTG
#define KUIT_NUMINTG
Definition: kuitsemantics_p.h:87
uintn
qulonglong uintn
Definition: klocalizedstring.cpp:54
QString::toInt
int toInt(bool *ok, int base) const
QString::isEmpty
bool isEmpty() const
pluraln
qulonglong pluraln
Definition: klocalizedstring.cpp:52
KLibrary
Thin wrapper around QLibrary; you should rarely use this directly, see KPluginLoader for higher-level...
Definition: klibrary.h:38
KLocale::country
QString country() const
Returns the country code of the country where the user lives.
Definition: klocale.cpp:116
QString
QList< QVariant >
QStringList
KLocale::translateRawFrom
void translateRawFrom(const char *catname, const char *msg, QString *lang, QString *trans) const
Definition: klocale.cpp:158
QLibrary::load
bool load()
QLatin1Char
ki18ncp
KLocalizedString ki18ncp(const char *ctxt, const char *singular, const char *plural)
Creates localized string from a given plural and singular form, with added context.
Definition: klocalizedstring.cpp:939
KGlobal::locale
KLocale * locale()
Returns the global locale object.
Definition: kglobal.cpp:170
ktranscript_p.h
kcatalogname_p.h
QVector::at
const T & at(int i) const
KLibrary::resolveFunction
void_function_ptr resolveFunction(const char *name)
Looks up a symbol from the library.
Definition: klibrary.cpp:181
QString::mid
QString mid(int position, int n) const
QVector
KLocale
KLocale provides support for country specific stuff like the national language.
Definition: klocale.h:69
kLocaleMutex
QMutex * kLocaleMutex()
Definition: klocale_kde.cpp:3319
QLatin1String
klocalizedstring.h
QMutexLocker
kstandarddirs.h
ki18nc
KLocalizedString ki18nc(const char *ctxt, const char *msg)
Creates localized string from a given message, with added context.
Definition: klocalizedstring.cpp:929
QList::last
T & last()
KTranscript
class for supporting programmable translations
Definition: ktranscript_p.h:38
KGlobal::hasMainComponent
bool hasMainComponent()
Definition: kglobal.cpp:151
QString::length
int length() const
KLocalizedString::operator=
KLocalizedString & operator=(const KLocalizedString &rhs)
Assignment operator.
Definition: klocalizedstring.cpp:173
QString::left
QString left(int n) const
KLocalizedString::subs
KLocalizedString subs(int a, int fieldWidth=0, int base=10, const QChar &fillChar=QLatin1Char(' ')) const
Substitutes an int argument into the message.
Definition: klocalizedstring.cpp:792
QString::fromLatin1
QString fromLatin1(const char *str, int size)
QVariant::isValid
bool isValid() const
kDebug
#define kDebug
Definition: kdebug.h:316
KLocalizedString::KLocalizedString
KLocalizedString()
Constructs an empty message, which is not valid for finalization.
Definition: klocalizedstring.cpp:148
intn
qlonglong intn
Definition: klocalizedstring.cpp:53
KLibrary::unload
bool unload()
Definition: klibrary.h:79
klibrary.h
QVector::size
int size() const
QString::arg
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
KLocalizedString
Class for producing and handling localized messages.
Definition: klocalizedstring.h:299
realn
double realn
Definition: klocalizedstring.cpp:55
KLocale::defaultLanguage
static QString defaultLanguage()
Returns the name of the internal language.
Definition: klocale.cpp:615
wrapNum
static QString wrapNum(const QString &tag, const QString &numstr, int fieldWidth, const QChar &fillChar)
Definition: klocalizedstring.cpp:777
QLibrary::errorString
QString errorString() const
QVariant
QString::toUtf8
QByteArray toUtf8() const
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:22:11 by doxygen 1.8.7 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 API Reference

Skip menu "kdelibs 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

Search



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