KVirc – next generation IRC client
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1192 lines
39 KiB

  1. //=============================================================================
  2. //
  3. // File : kvi_locale.cpp
  4. // Creation date : Fri Mar 19 1999 19:08:41 by Szymon Stefanek
  5. //
  6. // This file is part of the KVirc irc client distribution
  7. // Copyright (C) 1999-2002 Szymon Stefanek (pragma at kvirc dot net)
  8. //
  9. // This program is FREE software. You can redistribute it and/or
  10. // modify it under the terms of the GNU General Public License
  11. // as published by the Free Software Foundation; either version 2
  12. // of the License, or (at your opinion) any later version.
  13. //
  14. // This program is distributed in the HOPE that it will be USEFUL,
  15. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  17. // See the GNU General Public License for more details.
  18. //
  19. // You should have received a copy of the GNU General Public License
  20. // along with this program. If not, write to the Free Software Foundation,
  21. // Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  22. //
  23. //=============================================================================
  24. #define __KVILIB__
  25. //#define _KVI_DEBUG_CHECK_RANGE_
  26. #include "kvi_debug.h"
  27. #include "kvi_malloc.h"
  28. #include "kvi_bswap.h"
  29. #define _KVI_LOCALE_CPP_
  30. #include "kvi_locale.h"
  31. #include <tqglobal.h> //for tqDebug()
  32. #include <tqtextcodec.h>
  33. #include <tqdir.h>
  34. #ifdef COMPILE_USE_QT4
  35. #include <tqlocale.h>
  36. #endif
  37. #include "kvi_string.h"
  38. #include "kvi_qcstring.h"
  39. #include "kvi_env.h"
  40. #include "kvi_fileutils.h"
  41. #include "kvi_file.h"
  42. KVILIB_API KviMessageCatalogue * g_pMainCatalogue = 0;
  43. static KviStr g_szLang;
  44. static KviTranslator * g_pTranslator = 0;
  45. static KviPointerHashTable<const char *,KviMessageCatalogue> * g_pCatalogueDict = 0;
  46. static TQTextCodec * g_pUtf8TextCodec = 0;
  47. /////////////////////////////////////////////////////////////////////////////////////////////////////
  48. //
  49. // The following code was extracted and adapted from gutf8.c
  50. // from the GNU GLIB2 package.
  51. //
  52. // gutf8.c - Operations on UTF-8 strings.
  53. //
  54. // Copyright (C) 1999 Tom Tromey
  55. // Copyright (C) 2000 Red Hat, Inc.
  56. //
  57. // This library is free software; you can redistribute it and/or
  58. // modify it under the terms of the GNU Lesser General Public
  59. // License as published by the Free Software Foundation; either
  60. // version 2 of the License, or (at your option) any later version.
  61. //
  62. // This library is distributed in the hope that it will be useful,
  63. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  64. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  65. // Lesser General Public License for more details.
  66. //
  67. // You should have received a copy of the GNU Lesser General Public
  68. // License along with this library; if not, write to the
  69. // Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  70. // Boston, MA 02110-1301, USA.
  71. //
  72. /////////////////////////////////////////////////////////////////////////////////////////////////////
  73. typedef char gchar;
  74. typedef unsigned char guchar;
  75. typedef signed int gssize;
  76. typedef unsigned int gunichar;
  77. #define UNICODE_VALID(Char) \
  78. ((Char) < 0x110000 && \
  79. (((Char) & 0xFFFFF800) != 0xD800) && \
  80. ((Char) < 0xFDD0 || (Char) > 0xFDEF) && \
  81. ((Char) & 0xFFFE) != 0xFFFE)
  82. #define CONTINUATION_CHAR \
  83. if ((*(guchar *)p & 0xc0) != 0x80) /* 10xxxxxx */ \
  84. goto error; \
  85. val <<= 6; \
  86. val |= (*(guchar *)p) & 0x3f;
  87. static const char *
  88. fast_validate (const char *str)
  89. {
  90. gunichar val = 0;
  91. gunichar min = 0;
  92. const gchar *p;
  93. for (p = str; *p; p++)
  94. {
  95. if (*(guchar *)p < 128)
  96. /* done */;
  97. else
  98. {
  99. const gchar *last;
  100. last = p;
  101. if ((*(guchar *)p & 0xe0) == 0xc0) /* 110xxxxx */
  102. {
  103. if ((*(guchar *)p & 0x1e) == 0)
  104. goto error;
  105. p++;
  106. if ((*(guchar *)p & 0xc0) != 0x80) /* 10xxxxxx */
  107. goto error;
  108. }
  109. else
  110. {
  111. if ((*(guchar *)p & 0xf0) == 0xe0) /* 1110xxxx */
  112. {
  113. min = (1 << 11);
  114. val = *(guchar *)p & 0x0f;
  115. goto TWO_REMAINING;
  116. }
  117. else if ((*(guchar *)p & 0xf8) == 0xf0) /* 11110xxx */
  118. {
  119. min = (1 << 16);
  120. val = *(guchar *)p & 0x07;
  121. }
  122. else
  123. goto error;
  124. p++;
  125. CONTINUATION_CHAR;
  126. TWO_REMAINING:
  127. p++;
  128. CONTINUATION_CHAR;
  129. p++;
  130. CONTINUATION_CHAR;
  131. if (val < min)
  132. goto error;
  133. if (!UNICODE_VALID(val))
  134. goto error;
  135. }
  136. continue;
  137. error:
  138. return last;
  139. }
  140. }
  141. return p;
  142. }
  143. static const gchar *
  144. fast_validate_len (const char *str,
  145. gssize max_len)
  146. {
  147. gunichar val = 0;
  148. gunichar min = 0;
  149. const gchar *p;
  150. for (p = str; (max_len < 0 || (p - str) < max_len) && *p; p++)
  151. {
  152. if (*(guchar *)p < 128)
  153. /* done */;
  154. else
  155. {
  156. const gchar *last;
  157. last = p;
  158. if ((*(guchar *)p & 0xe0) == 0xc0) /* 110xxxxx */
  159. {
  160. if (max_len >= 0 && max_len - (p - str) < 2)
  161. goto error;
  162. if ((*(guchar *)p & 0x1e) == 0)
  163. goto error;
  164. p++;
  165. if ((*(guchar *)p & 0xc0) != 0x80) /* 10xxxxxx */
  166. goto error;
  167. }
  168. else
  169. {
  170. if ((*(guchar *)p & 0xf0) == 0xe0) /* 1110xxxx */
  171. {
  172. if (max_len >= 0 && max_len - (p - str) < 3)
  173. goto error;
  174. min = (1 << 11);
  175. val = *(guchar *)p & 0x0f;
  176. goto TWO_REMAINING;
  177. }
  178. else if ((*(guchar *)p & 0xf8) == 0xf0) /* 11110xxx */
  179. {
  180. if (max_len >= 0 && max_len - (p - str) < 4)
  181. goto error;
  182. min = (1 << 16);
  183. val = *(guchar *)p & 0x07;
  184. }
  185. else
  186. goto error;
  187. p++;
  188. CONTINUATION_CHAR;
  189. TWO_REMAINING:
  190. p++;
  191. CONTINUATION_CHAR;
  192. p++;
  193. CONTINUATION_CHAR;
  194. if (val < min)
  195. goto error;
  196. if (!UNICODE_VALID(val))
  197. goto error;
  198. }
  199. continue;
  200. error:
  201. return last;
  202. }
  203. }
  204. return p;
  205. }
  206. static bool g_utf8_validate (const char *str,
  207. gssize max_len,
  208. const gchar **end)
  209. {
  210. const gchar *p;
  211. if (max_len < 0)
  212. p = fast_validate (str);
  213. else
  214. p = fast_validate_len (str, max_len);
  215. if (end)
  216. *end = p;
  217. if ((max_len >= 0 && p != str + max_len) ||
  218. (max_len < 0 && *p != '\0'))
  219. return false;
  220. else
  221. return true;
  222. }
  223. ///////////////////////////////////////////////////////////////////////////////////////////////
  224. // End of gutf8.c
  225. ///////////////////////////////////////////////////////////////////////////////////////////////
  226. class KviSmartTextCodec : public TQTextCodec
  227. {
  228. protected:
  229. KviTQCString m_szName;
  230. TQTextCodec * m_pRecvCodec;
  231. TQTextCodec * m_pSendCodec;
  232. public:
  233. KviSmartTextCodec(const char * szName,const char * szChildCodecName,bool bSendInUtf8)
  234. : TQTextCodec()
  235. {
  236. m_szName = szName;
  237. if(!g_pUtf8TextCodec)
  238. {
  239. g_pUtf8TextCodec = TQTextCodec::codecForName("UTF-8");
  240. if(!g_pUtf8TextCodec)
  241. {
  242. tqDebug("Can't find the global utf8 text codec!");
  243. g_pUtf8TextCodec = TQTextCodec::codecForLocale(); // try anything else...
  244. }
  245. }
  246. m_pRecvCodec = TQTextCodec::codecForName(szChildCodecName);
  247. if(!m_pRecvCodec)
  248. {
  249. tqDebug("Can't find the codec for name %s (composite codec creation)",szName);
  250. m_pRecvCodec = g_pUtf8TextCodec;
  251. }
  252. if(bSendInUtf8)
  253. m_pSendCodec = g_pUtf8TextCodec;
  254. else
  255. m_pSendCodec = m_pRecvCodec;
  256. }
  257. public:
  258. bool ok(){ return m_pRecvCodec && g_pUtf8TextCodec; };
  259. virtual int mibEnum () const { return 0; };
  260. #ifdef COMPILE_USE_QT4
  261. virtual TQByteArray name() const { return m_szName; };
  262. protected:
  263. virtual TQByteArray convertFromUnicode(const TQChar * input,int number,ConverterState * state) const
  264. {
  265. return m_pSendCodec->fromUnicode(input,number,state);
  266. }
  267. virtual TQString convertToUnicode(const char * chars,int len,ConverterState * state) const
  268. {
  269. if(g_utf8_validate(chars,len,NULL))return g_pUtf8TextCodec->toUnicode(chars,len,state);
  270. return m_pRecvCodec->toUnicode(chars,len,state);
  271. }
  272. #else
  273. public:
  274. virtual const char * mimeName () const { return m_pRecvCodec->mimeName(); };
  275. virtual const char * name () const { return m_szName.data(); };
  276. virtual TQTextDecoder * makeDecoder () const { return m_pRecvCodec->makeDecoder(); };
  277. virtual TQTextEncoder * makeEncoder () const { return m_pSendCodec->makeEncoder(); };
  278. TQCString fromUnicode (const TQString & uc) const { return m_pSendCodec->fromUnicode(uc); };
  279. virtual TQCString fromUnicode (const TQString & uc,int & lenInOut) const { return m_pSendCodec->fromUnicode(uc,lenInOut); };
  280. TQString toUnicode(const char * chars) const
  281. {
  282. if(g_utf8_validate(chars,-1,NULL))return g_pUtf8TextCodec->toUnicode(chars);
  283. return m_pRecvCodec->toUnicode(chars);
  284. };
  285. virtual TQString toUnicode(const char * chars,int len) const
  286. {
  287. if(g_utf8_validate(chars,len,NULL))return g_pUtf8TextCodec->toUnicode(chars,len);
  288. return m_pRecvCodec->toUnicode(chars,len);
  289. };
  290. TQString toUnicode(const TQByteArray & a,int len) const
  291. {
  292. if(g_utf8_validate(a.data(),len,NULL))return g_pUtf8TextCodec->toUnicode(a,len);
  293. return m_pRecvCodec->toUnicode(a,len);
  294. };
  295. TQString toUnicode(const TQByteArray & a) const
  296. {
  297. if(g_utf8_validate(a.data(),a.size(),NULL))return g_pUtf8TextCodec->toUnicode(a);
  298. return m_pRecvCodec->toUnicode(a);
  299. };
  300. TQString toUnicode(const TQCString & a,int len) const
  301. {
  302. if(g_utf8_validate(a.data(),len,NULL))return g_pUtf8TextCodec->toUnicode(a,len);
  303. return m_pRecvCodec->toUnicode(a,len);
  304. };
  305. TQString toUnicode(const TQCString & a) const
  306. {
  307. if(g_utf8_validate(a.data(),-1,NULL))return g_pUtf8TextCodec->toUnicode(a);
  308. return m_pRecvCodec->toUnicode(a);
  309. };
  310. virtual bool canEncode(TQChar ch) const { return m_pSendCodec->canEncode(ch); };
  311. virtual bool canEncode(const TQString &s) const { return m_pSendCodec->canEncode(s); };
  312. virtual int heuristicContentMatch(const char * chars,int len) const
  313. {
  314. int iii = g_pUtf8TextCodec->heuristicContentMatch(chars,len);
  315. if(iii < 0)return m_pRecvCodec->heuristicContentMatch(chars,len);
  316. return iii;
  317. }
  318. virtual int heuristicNameMatch(const char * hint) const { return 0; };
  319. #endif
  320. };
  321. static KviPointerHashTable<const char *,KviSmartTextCodec> * g_pSmartCodecDict = 0;
  322. /////////////////////////////////////////////////////////////////////////////////////////////////////
  323. //
  324. // The following code was extracted and adapted from gettext.h and gettextP.h
  325. // from the GNU gettext package.
  326. //
  327. // Internal header for GNU gettext internationalization functions.
  328. // Copyright (C) 1995, 1997 Free Software Foundation, Inc.
  329. //
  330. // This program is free software; you can redistribute it and/or modify
  331. // it under the terms of the GNU General Public License as published by
  332. // the Free Software Foundation; either version 2, or (at your option)
  333. // any later version.
  334. //
  335. // This program is distributed in the hope that it will be useful,
  336. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  337. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  338. // GNU General Public License for more details.
  339. //
  340. // You should have received a copy of the GNU Library General Public
  341. // License along with the GNU C Library; see the file COPYING.LIB. If not,
  342. // write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  343. // Boston, MA 02110-1301, USA.
  344. //
  345. /////////////////////////////////////////////////////////////////////////////////////////////////////
  346. #include <stdio.h>
  347. #if HAVE_LIMITS_H || _LIBC
  348. #include <limits.h>
  349. #endif
  350. // The magic number of the GNU message catalog format.
  351. #define KVI_LOCALE_MAGIC 0x950412de
  352. #define KVI_LOCALE_MAGIC_SWAPPED 0xde120495
  353. // Revision number of the currently used .mo (binary) file format.
  354. #define MO_REVISION_NUMBER 0
  355. // Header for binary .mo file format.
  356. struct GnuMoFileHeader
  357. {
  358. // The magic number.
  359. kvi_u32_t magic;
  360. // The revision number of the file format.
  361. kvi_u32_t revision;
  362. // The number of strings pairs.
  363. kvi_u32_t nstrings;
  364. // Offset of table with start offsets of original strings.
  365. kvi_u32_t orig_tab_offset;
  366. // Offset of table with start offsets of translation strings.
  367. kvi_u32_t trans_tab_offset;
  368. // Size of hashing table.
  369. kvi_u32_t hash_tab_size;
  370. // Offset of first hashing entry.
  371. kvi_u32_t hash_tab_offset;
  372. };
  373. struct GnuMoStringDescriptor
  374. {
  375. // Length of addressed string.
  376. kvi_u32_t length;
  377. // Offset of string in file.
  378. kvi_u32_t offset;
  379. };
  380. #define KVI_SWAP_IF_NEEDED(flag,value) (flag ? kvi_swap32(value) : (value))
  381. ///////////////////////////////////////////////////////////////////////////////////////////////
  382. // End of gettext.h & gettextP.h
  383. ///////////////////////////////////////////////////////////////////////////////////////////////
  384. // HELPERS
  385. static int somePrimeNumbers[90]=
  386. {
  387. 257 , 521 , 769 , 1031, 1087, 1091, 1103, 1117, 1123, 1151, // Incomplete *.mo files
  388. 1163, 1171, 1181, 1193, 1201, 1213, 1217, 1223, 1229, 1231, // Complete *.mo files
  389. 1237, 1249, 1259, 1277, 1283, 1289, 1291, 1297, 1307, 1319,
  390. 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1433,
  391. 1447, 1459, 1471, 1481, 1493, 1511, 1523, 1531, 1543, 1553,
  392. 1567, 1571, 1583, 1597, 1609, 1619, 1627, 1637, 1657, 1667, // Too big for KVIrc *.mo files
  393. 1693, 1709, 1721, 1733, 1741, 1753, 1777, 1789, 1811, 1831,
  394. 1907, 2069, 2111, 2221, 2309, 2441, 2531, 2617, 2731, 2837,
  395. 2903, 3121, 3329, 3331, 3767, 4127, 5051, 6089, 7039, 9973
  396. };
  397. int kvi_getFirstBiggerPrime(int number)
  398. {
  399. for(int i=0;i<90;i++){
  400. if(somePrimeNumbers[i] >= number)return somePrimeNumbers[i];
  401. }
  402. return 9973; //error!
  403. }
  404. KviMessageCatalogue::KviMessageCatalogue()
  405. {
  406. //m_uEncoding = 0;
  407. m_pTextCodec = TQTextCodec::codecForLocale();
  408. //m_pMessages = new KviPointerHashTable<const char *,KviTranslationEntry>(1123,true,false); // dictSize, case sensitive , don't copy keys
  409. m_pMessages = new KviPointerHashTable<const char *,KviTranslationEntry>(32,true,false); // dictSize, case sensitive , don't copy keys
  410. m_pMessages->setAutoDelete(true);
  411. }
  412. KviMessageCatalogue::~KviMessageCatalogue()
  413. {
  414. if(m_pMessages)
  415. delete m_pMessages;
  416. }
  417. bool KviMessageCatalogue::load(const TQString& name)
  418. {
  419. TQString szCatalogueFile(name);
  420. // Try to load the header
  421. KviFile f(szCatalogueFile);
  422. if(!f.openForReading())
  423. {
  424. tqDebug("[KviLocale]: Failed to open the messages file %s: probably doesn't exist",KviTQString::toUtf8(szCatalogueFile).data());
  425. return false;
  426. }
  427. GnuMoFileHeader hdr;
  428. if(f.readBlock((char *)&hdr,sizeof(GnuMoFileHeader)) < (int)sizeof(GnuMoFileHeader))
  429. {
  430. tqDebug("KviLocale: Failed to read header of %s",KviTQString::toUtf8(szCatalogueFile).data());
  431. f.close();
  432. return false;
  433. }
  434. bool bMustSwap = false;
  435. if(hdr.magic != KVI_LOCALE_MAGIC)
  436. {
  437. if(hdr.magic == KVI_LOCALE_MAGIC_SWAPPED)
  438. {
  439. tqDebug("KviLocale: Swapped magic for file %s: swapping data too",KviTQString::toUtf8(szCatalogueFile).data());
  440. bMustSwap = true;
  441. } else {
  442. tqDebug("KviLocale: Bad locale magic for file %s: not a *.mo file ?",KviTQString::toUtf8(szCatalogueFile).data());
  443. f.close();
  444. return false;
  445. }
  446. }
  447. if(KVI_SWAP_IF_NEEDED(bMustSwap,hdr.revision) != MO_REVISION_NUMBER)
  448. {
  449. tqDebug("KviLocale: Invalid *.mo file revision number for file %s",KviTQString::toUtf8(szCatalogueFile).data());
  450. f.close();
  451. return false;
  452. }
  453. int numberOfStrings = KVI_SWAP_IF_NEEDED(bMustSwap,hdr.nstrings);
  454. if(numberOfStrings <= 0)
  455. {
  456. tqDebug("KviLocale: No translated messages found in file %s",KviTQString::toUtf8(szCatalogueFile).data());
  457. f.close();
  458. return false;
  459. }
  460. if(numberOfStrings >= 9972)
  461. {
  462. tqDebug("Number of strings too big...sure that it is a KVIrc catalog file ?");
  463. numberOfStrings = 9972;
  464. }
  465. // return back
  466. f.seek(0);
  467. unsigned int fSize = f.size();
  468. char * buffer = (char *)kvi_malloc(fSize);
  469. // FIXME: maybe read it in blocks eh ?
  470. if(f.readBlock(buffer,fSize) < (int)fSize)
  471. {
  472. tqDebug("KviLocale: Error while reading the translation file %s",KviTQString::toUtf8(szCatalogueFile).data());
  473. kvi_free(buffer);
  474. f.close();
  475. return false;
  476. }
  477. // Check for broken *.mo files
  478. if(fSize < (24 + (sizeof(GnuMoStringDescriptor) * numberOfStrings)))
  479. {
  480. tqDebug("KviLocale: Broken translation file %s (too small for all descriptors)",KviTQString::toUtf8(szCatalogueFile).data());
  481. kvi_free(buffer);
  482. f.close();
  483. return false;
  484. }
  485. GnuMoStringDescriptor * origDescriptor = (GnuMoStringDescriptor *)(buffer + KVI_SWAP_IF_NEEDED(bMustSwap,hdr.orig_tab_offset));
  486. GnuMoStringDescriptor * transDescriptor = (GnuMoStringDescriptor *)(buffer + KVI_SWAP_IF_NEEDED(bMustSwap,hdr.trans_tab_offset));
  487. // Check again for broken *.mo files
  488. int expectedFileSize = KVI_SWAP_IF_NEEDED(bMustSwap,transDescriptor[numberOfStrings - 1].offset) +
  489. KVI_SWAP_IF_NEEDED(bMustSwap,transDescriptor[numberOfStrings - 1].length);
  490. if(fSize < (unsigned int)expectedFileSize)
  491. {
  492. tqDebug("KviLocale: Broken translation file %s (too small for all the message strings)",KviTQString::toUtf8(szCatalogueFile).data());
  493. kvi_free(buffer);
  494. f.close();
  495. return false;
  496. }
  497. // Ok...we can run now
  498. int dictSize = kvi_getFirstBiggerPrime(numberOfStrings);
  499. if(m_pMessages)
  500. delete m_pMessages;
  501. m_pMessages = new KviPointerHashTable<const char *,KviTranslationEntry>(dictSize,true,false); // dictSize, case sensitive , don't copy keys
  502. m_pMessages->setAutoDelete(true);
  503. KviStr szHeader;
  504. for(int i=0;i < numberOfStrings;i++)
  505. {
  506. // FIXME: "Check for NULL inside strings here ?"
  507. //tqDebug("original seems to be at %u and %u byttes long",KVI_SWAP_IF_NEEDED(bMustSwap,origDescriptor[i].offset),
  508. // KVI_SWAP_IF_NEEDED(bMustSwap,origDescriptor[i].length));
  509. //tqDebug("translated seems to be at %u and %u byttes long",KVI_SWAP_IF_NEEDED(bMustSwap,transDescriptor[i].offset),
  510. // KVI_SWAP_IF_NEEDED(bMustSwap,transDescriptor[i].length));
  511. KviTranslationEntry * e = new KviTranslationEntry(
  512. (char *)(buffer + KVI_SWAP_IF_NEEDED(bMustSwap,origDescriptor[i].offset)),
  513. KVI_SWAP_IF_NEEDED(bMustSwap,origDescriptor[i].length),
  514. (char *)(buffer + KVI_SWAP_IF_NEEDED(bMustSwap,transDescriptor[i].offset)),
  515. KVI_SWAP_IF_NEEDED(bMustSwap,transDescriptor[i].length));
  516. // In some (or all?) *.mo files the first string
  517. // is zero bytes long and the translated one contains
  518. // informations about the translation
  519. if(e->m_szKey.len() == 0)
  520. {
  521. szHeader = e->m_szEncodedTranslation;
  522. delete e;
  523. continue;
  524. }
  525. m_pMessages->insert(e->m_szKey.ptr(),e);
  526. }
  527. kvi_free(buffer);
  528. f.close();
  529. m_pTextCodec = 0;
  530. // find out the text encoding , if possible
  531. if(szHeader.hasData())
  532. {
  533. // find "charset=*\n"
  534. int idx = szHeader.findFirstIdx("charset=");
  535. if(idx != -1)
  536. {
  537. szHeader.cutLeft(idx + 8);
  538. szHeader.cutFromFirst('\n');
  539. szHeader.stripWhiteSpace();
  540. m_pTextCodec = KviLocale::codecForName(szHeader.ptr());
  541. if(!m_pTextCodec)
  542. {
  543. tqDebug("Can't find the codec for charset=%s",szHeader.ptr());
  544. tqDebug("Falling back to codecForLocale()");
  545. m_pTextCodec = TQTextCodec::codecForLocale();
  546. }
  547. }
  548. }
  549. if(!m_pTextCodec)
  550. {
  551. tqDebug("The message catalogue does not have a \"charset\" header");
  552. tqDebug("Assuming utf8"); // FIXME: or codecForLocale() ?
  553. m_pTextCodec = TQTextCodec::codecForName("UTF-8");
  554. }
  555. return true;
  556. }
  557. const char * KviMessageCatalogue::translate(const char *text)
  558. {
  559. KviTranslationEntry * aux = m_pMessages->find(text);
  560. if(aux)return aux->m_szEncodedTranslation.ptr();
  561. return text;
  562. }
  563. const TQString & KviMessageCatalogue::translateToTQString(const char *text)
  564. {
  565. KviTranslationEntry * aux = m_pMessages->find(text);
  566. if(aux)
  567. {
  568. if(aux->m_pTQTranslation)return *(aux->m_pTQTranslation);
  569. aux->m_pTQTranslation = new TQString(m_pTextCodec->toUnicode(aux->m_szEncodedTranslation.ptr()));
  570. return *(aux->m_pTQTranslation);
  571. }
  572. // no translation is available: let's avoid continous string decoding
  573. aux = new KviTranslationEntry(text);
  574. m_pMessages->insert(aux->m_szKey.ptr(),aux);
  575. aux->m_pTQTranslation = new TQString(m_pTextCodec->toUnicode(aux->m_szEncodedTranslation.ptr()));
  576. return *(aux->m_pTQTranslation);
  577. }
  578. namespace KviLocale
  579. {
  580. #ifndef TQT_NO_BIG_CODECS
  581. #define NUM_ENCODINGS 109
  582. #else
  583. #define NUM_ENCODINGS 85
  584. #endif
  585. static EncodingDescription supported_encodings[]=
  586. {
  587. { "UTF-8" , 0 , 0 , "8-bit Unicode" },
  588. { "ISO-8859-1" , 0 , 0 , "Western, Latin-1" },
  589. { "ISO-8859-2" , 0 , 0 , "Central European 1" },
  590. { "ISO-8859-3" , 0 , 0 , "Central European 2" },
  591. { "ISO-8859-4" , 0 , 0 , "Baltic, Standard" },
  592. { "ISO-8859-5" , 0 , 0 , "Cyrillic, ISO" },
  593. { "ISO-8859-6" , 0 , 0 , "Arabic, Standard" },
  594. { "ISO-8859-7" , 0 , 0 , "Greek" },
  595. { "ISO-8859-8" , 0 , 0 , "Hebrew, visually ordered" },
  596. { "ISO-8859-8-i" , 0 , 0 , "Hebrew, logically ordered" },
  597. { "ISO-8859-9" , 0 , 0 , "Turkish, Latin-5" },
  598. { "ISO-8859-15" , 0 , 0 , "Western, Latin-1 + Euro" },
  599. { "KOI8-R" , 0 , 0 , "Cyrillic, KOI" },
  600. { "KOI8-U" , 0 , 0 , "Ukrainian" },
  601. { "CP-1250" , 0 , 0 , "Central European 3" },
  602. { "CP-1251" , 0 , 0 , "Cyrillic, Windows" },
  603. { "CP-1252" , 0 , 0 , "Western, CP" },
  604. { "CP-1253" , 0 , 0 , "Greek, CP" },
  605. { "CP-1256" , 0 , 0 , "Arabic, CP" },
  606. { "CP-1257" , 0 , 0 , "Baltic, CP" },
  607. { "CP-1255" , 0 , 0 , "Hebrew, CP" },
  608. { "CP-1254" , 0 , 0 , "Turkish, CP" },
  609. { "TIS-620" , 0 , 0 , "Thai" },
  610. #ifndef TQT_NO_BIG_CODECS
  611. { "Big5" , 0 , 0 , "Chinese Traditional" },
  612. { "Big5-HKSCS" , 0 , 0 , "Chinese Traditional, Hong Kong" },
  613. { "GB18030" , 0 , 0 , "Chinese Simplified" },
  614. { "JIS7" , 0 , 0 , "Japanese (JIS7)" },
  615. { "Shift-JIS" , 0 , 0 , "Japanese (Shift-JIS)" },
  616. { "EUC-JP" , 0 , 0 , "Japanese (EUC-JP)" },
  617. { "EUC-KR" , 0 , 0 , "Korean" },
  618. { "TSCII" , 0 , 0 , "Tamil" },
  619. #endif
  620. { "ISO-8859-10" , 0 , 0 , "ISO-8859-10" },
  621. { "ISO-8859-13" , 0 , 0 , "ISO-8859-13" },
  622. { "ISO-8859-14" , 0 , 0 , "ISO-8859-14" },
  623. { "IBM-850" , 0 , 0 , "IBM-850" },
  624. { "IBM-866" , 0 , 0 , "IBM-866" },
  625. { "CP874" , 0 , 0 , "CP874" },
  626. // smart codecs that send in the local charset
  627. { "ISO-8859-1 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Western Latin-1, O: Western Latin-1" },
  628. { "ISO-8859-2 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Central European 1, O: Central European 1" },
  629. { "ISO-8859-3 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Central European 2, O: Central European 2" },
  630. { "ISO-8859-4 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Baltic, Standard, O: Baltic, Standard" },
  631. { "ISO-8859-5 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Cyrillic, ISO, O: Cyrillic, ISO" },
  632. { "ISO-8859-6 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Arabic, Standard, O: Arabic, Standard" },
  633. { "ISO-8859-7 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Greek, O: Greek" },
  634. { "ISO-8859-8 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Hebrew, visually ordered, O: Hebrew, visually ordered" },
  635. { "ISO-8859-8-i [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Hebrew, logically ordered, O: Hebrew, logically ordered" },
  636. { "ISO-8859-9 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Turkish, Latin-5, O: Turkish, Latin-5" },
  637. { "ISO-8859-15 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Western, Latin-1 + Euro, O: Western, Latin-1 + Euro" },
  638. { "KOI8-R [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Cyrillic, KOI, O: Cyrillic, KOI" },
  639. { "KOI8-U [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Ukrainian, O: Ukrainian" },
  640. { "CP-1250 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Central European 3, O: Central European 3" },
  641. { "CP-1251 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Cyrillic, Windows, O: Cyrillic, Windows" },
  642. { "CP-1252 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Western, CP, O: Western, CP" },
  643. { "CP-1253 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Greek, CP, O: Greek, CP" },
  644. { "CP-1256 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Arabic, CP, O: Arabic, CP" },
  645. { "CP-1257 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Baltic, CP, O: Baltic, CP" },
  646. { "CP-1255 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Hebrew, CP, O: Hebrew, CP" },
  647. { "CP-1254 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Turkish, CP, O: Turkish, CP" },
  648. { "TIS-620 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Thai, O: Thai" },
  649. #ifndef TQT_NO_BIG_CODECS
  650. { "Big5 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Chinese Traditional, O: Chinese Traditional" },
  651. { "Big5-HKSCS [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Chinese Traditional, Hong Kong, O: Chinese Traditional, Hong Kong" },
  652. { "GB18030 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Chinese Simplified, O: Chinese Simplified" },
  653. { "JIS7 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Japanese (JIS7), O: Japanese " },
  654. { "Shift-JIS [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Japanese (Shift-JIS), O: Japanese (Shift-JIS)" },
  655. { "EUC-JP [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Japanese (EUC-JP), O: Japanese (EUC-JP)" },
  656. { "EUC-KR [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Korean, O: Korean" },
  657. { "TSCII [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Tamil, O: Tamil" },
  658. #endif
  659. { "ISO-8859-10 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / ISO-8859-10, O: ISO-8859-10" },
  660. { "ISO-8859-13 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / ISO-8859-13, O: ISO-8859-13" },
  661. { "ISO-8859-14 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / ISO-8859-14, O: ISO-8859-14" },
  662. { "IBM-850 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / IBM-850, O: IBM-850" },
  663. { "IBM-866 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / IBM-866, O: IBM-866" },
  664. { "CP874 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / CP874, O: CP874" },
  665. // smart codecs that send in utf8
  666. { "UTF-8 [ISO-8859-1]" , 1 , 1 , "I: 8-bit Unicode / Western Latin-1, O: 8-bit Unicode" },
  667. { "UTF-8 [ISO-8859-2]" , 1 , 1 , "I: 8-bit Unicode / Central European 1, O: 8-bit Unicode" },
  668. { "UTF-8 [ISO-8859-3]" , 1 , 1 , "I: 8-bit Unicode / Central European 2, O: 8-bit Unicode" },
  669. { "UTF-8 [ISO-8859-4]" , 1 , 1 , "I: 8-bit Unicode / Baltic, Standard, O: 8-bit Unicode" },
  670. { "UTF-8 [ISO-8859-5]" , 1 , 1 , "I: 8-bit Unicode / Cyrillic, ISO, O: 8-bit Unicode" },
  671. { "UTF-8 [ISO-8859-6]" , 1 , 1 , "I: 8-bit Unicode / Arabic, Standard, O: 8-bit Unicode" },
  672. { "UTF-8 [ISO-8859-7]" , 1 , 1 , "I: 8-bit Unicode / Greek, O: 8-bit Unicode" },
  673. { "UTF-8 [ISO-8859-8]" , 1 , 1 , "I: 8-bit Unicode / Hebrew, visually ordered, O: 8-bit Unicode" },
  674. { "UTF-8 [ISO-8859-8-i]" , 1 , 1 , "I: 8-bit Unicode / Hebrew, logically ordered, O: 8-bit Unicode" },
  675. { "UTF-8 [ISO-8859-9]" , 1 , 1 , "I: 8-bit Unicode / Turkish, Latin-5, O: 8-bit Unicode" },
  676. { "UTF-8 [ISO-8859-15]" , 1 , 1 , "I: 8-bit Unicode / Western, Latin-1 + Euro, O: 8-bit Unicode" },
  677. { "UTF-8 [KOI8-R]" , 1 , 1 , "I: 8-bit Unicode / Cyrillic, KOI, O: 8-bit Unicode" },
  678. { "UTF-8 [KOI8-U]" , 1 , 1 , "I: 8-bit Unicode / Ukrainian, O: 8-bit Unicode" },
  679. { "UTF-8 [CP-1250]" , 1 , 1 , "I: 8-bit Unicode / Central European 3, O: 8-bit Unicode" },
  680. { "UTF-8 [CP-1251]" , 1 , 1 , "I: 8-bit Unicode / Cyrillic, Windows, O: 8-bit Unicode" },
  681. { "UTF-8 [CP-1252]" , 1 , 1 , "I: 8-bit Unicode / Western, CP, O: 8-bit Unicode" },
  682. { "UTF-8 [CP-1253]" , 1 , 1 , "I: 8-bit Unicode / Greek, CP, O: 8-bit Unicode" },
  683. { "UTF-8 [CP-1256]" , 1 , 1 , "I: 8-bit Unicode / Arabic, CP, O: 8-bit Unicode" },
  684. { "UTF-8 [CP-1257]" , 1 , 1 , "I: 8-bit Unicode / Baltic, CP, O: 8-bit Unicode" },
  685. { "UTF-8 [CP-1255]" , 1 , 1 , "I: 8-bit Unicode / Hebrew, CP, O: 8-bit Unicode" },
  686. { "UTF-8 [CP-1254]" , 1 , 1 , "I: 8-bit Unicode / Turkish, CP, O: 8-bit Unicode" },
  687. { "UTF-8 [TIS-620]" , 1 , 1 , "I: 8-bit Unicode / Thai, O: 8-bit Unicode" },
  688. #ifndef TQT_NO_BIG_CODECS
  689. { "UTF-8 [Big5]" , 1 , 1 , "I: 8-bit Unicode / Chinese Traditional, O: 8-bit Unicode" },
  690. { "UTF-8 [Big5-HKSCS]" , 1 , 1 , "I: 8-bit Unicode / Chinese Traditional, Hong Kong, O: 8-bit Unicode" },
  691. { "UTF-8 [GB18030]" , 1 , 1 , "I: 8-bit Unicode / Chinese Simplified, O: 8-bit Unicode" },
  692. { "UTF-8 [JIS7]" , 1 , 1 , "I: 8-bit Unicode / Japanese (JIS7), O: 8-bit Unicode" },
  693. { "UTF-8 [Shift-JIS]" , 1 , 1 , "I: 8-bit Unicode / Japanese (Shift-JIS), O: Japanese (Shift-JIS)" },
  694. { "UTF-8 [EUC-JP]" , 1 , 1 , "I: 8-bit Unicode / Japanese (EUC-JP), O: Japanese (EUC-JP)" },
  695. { "UTF-8 [EUC-KR]" , 1 , 1 , "I: 8-bit Unicode / Korean, O: 8-bit Unicode" },
  696. { "UTF-8 [TSCII]" , 1 , 1 , "I: 8-bit Unicode / Tamil, O: 8-bit Unicode" },
  697. #endif
  698. { "UTF-8 [ISO-8859-10]" , 1 , 1 , "I: 8-bit Unicode / ISO-8859-10, O: 8-bit Unicode" },
  699. { "UTF-8 [ISO-8859-13]" , 1 , 1 , "I: 8-bit Unicode / ISO-8859-13, O: 8-bit Unicode" },
  700. { "UTF-8 [ISO-8859-14]" , 1 , 1 , "I: 8-bit Unicode / ISO-8859-14, O: 8-bit Unicode" },
  701. { "UTF-8 [IBM-850]" , 1 , 1 , "I: 8-bit Unicode / IBM-850, O: 8-bit Unicode" },
  702. { "UTF-8 [IBM-866]" , 1 , 1 , "I: 8-bit Unicode / IBM-866, O: 8-bit Unicode" },
  703. { "UTF-8 [CP874]" , 1 , 1 , "I: 8-bit Unicode / CP874, O: 8-bit Unicode" },
  704. { 0 , 0 , 0 , 0 }
  705. };
  706. EncodingDescription * encodingDescription(int iIdx)
  707. {
  708. if(iIdx > NUM_ENCODINGS)return &(supported_encodings[NUM_ENCODINGS]);
  709. return &(supported_encodings[iIdx]);
  710. }
  711. TQTextCodec * codecForName(const char * szName)
  712. {
  713. KviStr szTmp = szName;
  714. int idx = szTmp.findFirstIdx('[');
  715. if(idx != -1)
  716. {
  717. // composite codec: either UTF-8 [child codec] or child codec [UTF-8]
  718. KviSmartTextCodec * c = g_pSmartCodecDict->find(szName);
  719. if(c)return c;
  720. if(kvi_strEqualCIN("UTF-8 [",szName,7))
  721. {
  722. szTmp.replaceAll("UTF-8 [","");
  723. szTmp.replaceAll("]","");
  724. // smart codec that sends UTF-8
  725. c = new KviSmartTextCodec(szName,szTmp.ptr(),true);
  726. } else {
  727. szTmp.cutFromFirst(' ');
  728. // smart codec that sends child encoding
  729. c = new KviSmartTextCodec(szName,szTmp.ptr(),false);
  730. }
  731. if(c->ok())
  732. {
  733. g_pSmartCodecDict->replace(szName,c);
  734. return c;
  735. } else {
  736. delete c;
  737. }
  738. }
  739. return TQTextCodec::codecForName(szName);
  740. }
  741. const KviStr & localeName()
  742. {
  743. return g_szLang;
  744. }
  745. bool loadCatalogue(const TQString &name,const TQString &szLocaleDir)
  746. {
  747. //tqDebug("Looking up catalogue %s",name);
  748. if(g_pCatalogueDict->find(KviTQString::toUtf8(name).data()))return true; // already loaded
  749. TQString szBuffer;
  750. if(findCatalogue(szBuffer,name,szLocaleDir))
  751. {
  752. KviMessageCatalogue * c = new KviMessageCatalogue();
  753. if(c->load(szBuffer))
  754. {
  755. //tqDebug("KviLocale: loaded catalogue %s",name);
  756. g_pCatalogueDict->insert(KviTQString::toUtf8(name).data(),c);
  757. return true;
  758. }
  759. }
  760. return false;
  761. }
  762. bool unloadCatalogue(const TQString &name)
  763. {
  764. //tqDebug("Unloading catalogue : %s",name);
  765. return g_pCatalogueDict->remove(KviTQString::toUtf8(name).data());
  766. }
  767. bool findCatalogue(TQString &szBuffer,const TQString& name,const TQString& szLocaleDir)
  768. {
  769. KviStr szLocale = g_szLang;
  770. TQString szLocDir = szLocaleDir;
  771. KviTQString::ensureLastCharIs(szLocDir,KVI_PATH_SEPARATOR_CHAR);
  772. KviTQString::sprintf(szBuffer,"%Q%TQ_%s.mo",&szLocDir,&name,szLocale.ptr());
  773. if(KviFileUtils::fileExists(szBuffer))return true;
  774. if(szLocale.findFirstIdx('.') != -1)
  775. {
  776. // things like en_GB.utf8
  777. // kill them
  778. szLocale.cutFromFirst('.');
  779. KviTQString::sprintf(szBuffer,"%Q%TQ_%s.mo",&szLocDir,&name,szLocale.ptr());
  780. if(KviFileUtils::fileExists(szBuffer))return true;
  781. }
  782. if(szLocale.findFirstIdx('@') != -1)
  783. {
  784. // things like @euro ?
  785. // kill them
  786. szLocale.cutFromFirst('@');
  787. KviTQString::sprintf(szBuffer,"%Q%TQ_%s.mo",&szLocDir,&name,szLocale.ptr());
  788. if(KviFileUtils::fileExists(szBuffer))return true;
  789. }
  790. if(szLocale.findFirstIdx('_') != -1)
  791. {
  792. // things like en_GB
  793. // kill them
  794. szLocale.cutFromFirst('_');
  795. KviTQString::sprintf(szBuffer,"%Q%TQ_%s.mo",&szLocDir,&name,szLocale.ptr());
  796. if(KviFileUtils::fileExists(szBuffer))return true;
  797. }
  798. // try the lower case version too
  799. szLocale.toLower();
  800. KviTQString::sprintf(szBuffer,"%Q%TQ_%s.mo",&szLocDir,&name,szLocale.ptr());
  801. if(KviFileUtils::fileExists(szBuffer))return true;
  802. return false;
  803. }
  804. //
  805. // This function attempts to determine the current locale
  806. // and then load the corresponding translation file
  807. // from the KVIrc locale directory
  808. // Returns true if the locale was correctly set
  809. // i.e. the locale is C or POSIX (no translation needed)
  810. // or the locale is correctly defined and the
  811. // translation map was sucesfully loaded
  812. //
  813. void init(TQApplication * app,const TQString &localeDir)
  814. {
  815. // first of all try to find out the current locale
  816. g_szLang="";
  817. #ifdef COMPILE_USE_QT4
  818. TQString szLangFile=TQString("%1/.kvirc_force_locale").arg(TQDir::homePath());
  819. #else
  820. TQString szLangFile=TQString("%1/.kvirc_force_locale").arg(TQDir::homeDirPath());
  821. #endif
  822. if(KviFileUtils::fileExists(szLangFile))
  823. {
  824. TQString szTmp;
  825. KviFileUtils::readFile(szLangFile,szTmp);
  826. g_szLang=szTmp;
  827. }
  828. if(g_szLang.isEmpty())g_szLang = kvi_getenv("KVIRC_LANG");
  829. #ifdef COMPILE_USE_QT4
  830. if(g_szLang.isEmpty())g_szLang = TQLocale::system().name();
  831. #else
  832. if(g_szLang.isEmpty())g_szLang = TQTextCodec::locale();
  833. #endif
  834. if(g_szLang.isEmpty())g_szLang = kvi_getenv("LC_MESSAGES");
  835. if(g_szLang.isEmpty())g_szLang = kvi_getenv("LANG");
  836. if(g_szLang.isEmpty())g_szLang = "en";
  837. g_szLang.stripWhiteSpace();
  838. // the main catalogue is supposed to be kvirc_<language>.mo
  839. g_pMainCatalogue = new KviMessageCatalogue();
  840. // the catalogue dict
  841. g_pCatalogueDict = new KviPointerHashTable<const char *,KviMessageCatalogue>;
  842. g_pCatalogueDict->setAutoDelete(true);
  843. // the smart codec dict
  844. g_pSmartCodecDict = new KviPointerHashTable<const char *,KviSmartTextCodec>;
  845. // the TQt docs explicitly state that we shouldn't delete
  846. // the codecs by ourselves...
  847. g_pSmartCodecDict->setAutoDelete(false);
  848. if(g_szLang.hasData())
  849. {
  850. TQString szBuffer;
  851. if(findCatalogue(szBuffer,"kvirc",localeDir))
  852. {
  853. g_pMainCatalogue->load(szBuffer);
  854. g_pTranslator = new KviTranslator(TQT_TQOBJECT(app),"kvirc_translator");
  855. app->installTranslator(g_pTranslator);
  856. } else {
  857. KviStr szTmp = g_szLang;
  858. szTmp.cutFromFirst('.');
  859. szTmp.cutFromFirst('_');
  860. szTmp.cutFromFirst('@');
  861. szTmp.toLower();
  862. if(!(kvi_strEqualCI(szTmp.ptr(),"en") ||
  863. kvi_strEqualCI(szTmp.ptr(),"c") ||
  864. kvi_strEqualCI(szTmp.ptr(),"us") ||
  865. kvi_strEqualCI(szTmp.ptr(),"gb") ||
  866. kvi_strEqualCI(szTmp.ptr(),"posix")))
  867. {
  868. // FIXME: THIS IS NO LONGER VALID!!!
  869. tqDebug("Can't find the catalogue for locale \"%s\" (%s)",g_szLang.ptr(),szTmp.ptr());
  870. tqDebug("There is no such translation or the $LANG variable was incorrectly set");
  871. tqDebug("You can use $KVIRC_LANG to override the catalogue name");
  872. tqDebug("For example you can set KVIRC_LANG to it_IT to force usage of the it.mo catalogue");
  873. }
  874. }
  875. }
  876. //g_pTextCodec = TQTextCodec::codecForLocale();
  877. //if(!g_pTextCodec)g_pTextCodec = TQTextCodec::codecForLocale();
  878. }
  879. void done(TQApplication * app)
  880. {
  881. delete g_pMainCatalogue;
  882. delete g_pCatalogueDict;
  883. delete g_pSmartCodecDict;
  884. g_pMainCatalogue = 0;
  885. g_pCatalogueDict = 0;
  886. g_pSmartCodecDict = 0;
  887. if(g_pTranslator)
  888. {
  889. app->removeTranslator(g_pTranslator);
  890. delete g_pTranslator;
  891. g_pTranslator = 0;
  892. }
  893. }
  894. KviMessageCatalogue * getLoadedCatalogue(const TQString& name)
  895. {
  896. return g_pCatalogueDict->find(KviTQString::toUtf8(name).data());
  897. }
  898. const char * translate(const char * text,const char * context)
  899. {
  900. if(context)
  901. {
  902. KviMessageCatalogue * c = g_pCatalogueDict->find(context);
  903. if(!c)
  904. {
  905. // FIXME: Should really try to load the catalogue here!
  906. c = new KviMessageCatalogue();
  907. g_pCatalogueDict->insert(context,c);
  908. }
  909. return c->translate(text);
  910. }
  911. return g_pMainCatalogue->translate(text);
  912. }
  913. const TQString & translateToTQString(const char * text,const char * context)
  914. {
  915. if(context)
  916. {
  917. KviMessageCatalogue * c = g_pCatalogueDict->find(context);
  918. if(!c)
  919. {
  920. // FIXME: Should really try to load the catalogue here!
  921. c = new KviMessageCatalogue();
  922. g_pCatalogueDict->insert(context,c);
  923. }
  924. return c->translateToTQString(text);
  925. }
  926. return g_pMainCatalogue->translateToTQString(text);
  927. }
  928. };
  929. KviTranslator::KviTranslator(TQObject * par,const char * nam)
  930. #ifdef COMPILE_USE_QT4
  931. : TQTranslator(par)
  932. #else
  933. : TQTranslator(par,nam)
  934. #endif
  935. {
  936. }
  937. KviTranslator::~KviTranslator()
  938. {
  939. }
  940. #ifdef COMPILE_USE_QT4
  941. TQString KviTranslator::translate(const char *context,const char * message,const char * comment) const
  942. {
  943. // we ignore contexts and comments for qt translations
  944. return g_pMainCatalogue->translateToTQString(message);
  945. }
  946. #endif
  947. TQString KviTranslator::find(const char *context,const char * message) const
  948. {
  949. // we ignore contexts for qt translations
  950. return g_pMainCatalogue->translateToTQString(message);
  951. }
  952. #ifndef COMPILE_USE_QT4
  953. TQTranslatorMessage KviTranslator::findMessage(const char * context,const char * sourceText,const char * comment) const
  954. {
  955. // we ignore contexts for qt translations
  956. return TQTranslatorMessage(context,sourceText,comment,g_pMainCatalogue->translateToTQString(sourceText));
  957. }
  958. #endif
  959. #if 0
  960. // a fake table that will force these translations
  961. // to be included in the *.pot file
  962. static TQString fake_translations_table[]=
  963. {
  964. // global
  965. __tr2qs("OK"),
  966. __tr2qs("Cancel"),
  967. // color dialog
  968. __tr2qs("Select color"),
  969. __tr2qs("&Basic colors"),
  970. __tr2qs("&Custom colors"),
  971. __tr2qs("&Red"),
  972. __tr2qs("&Green"),
  973. __tr2qs("Bl&ue"),
  974. __tr2qs("&Define Custom Colors >>"),
  975. __tr2qs("&Add to Custom Colors"),
  976. // font dialog
  977. __tr2qs("Select Font"),
  978. __tr2qs("&Font"),
  979. __tr2qs("Font st&yle"),
  980. __tr2qs("&Size"),
  981. __tr2qs("Sample"),
  982. __tr2qs("Effects"),
  983. __tr2qs("Stri&keout"),
  984. __tr2qs("&Underline"),
  985. __tr2qs("Scr&ipt"),
  986. //File selector
  987. __tr2qs("Parent Directory"),
  988. __tr2qs("Back"),
  989. __tr2qs("Forward"),
  990. __tr2qs("Reload"),
  991. __tr2qs("New Directory"),
  992. __tr2qs("Bookmarks"),
  993. __tr2qs("Add Bookmark"),
  994. __tr2qs("&Edit Bookmarks"),
  995. __tr2qs("New Bookmark Folder..."),
  996. __tr2qs("Configure"),
  997. __tr2qs("Sorting"),
  998. __tr2qs("By Name"),
  999. __tr2qs("By Date"),
  1000. __tr2qs("By Size"),
  1001. __tr2qs("Reverse"),
  1002. __tr2qs("Directories First"),
  1003. __tr2qs("Case Insensitive"),
  1004. __tr2qs("Short View"),
  1005. __tr2qs("Detailed View"),
  1006. __tr2qs("Show Hidden Files"),
  1007. __tr2qs("Show Quick Access Navigation Panel"),
  1008. __tr2qs("Show Preview"),
  1009. __tr2qs("Separate Directories"),
  1010. __tr2qs("Often used directories"),
  1011. __tr2qs("Desktop"),
  1012. __tr2qs("Home Directory"),
  1013. __tr2qs("Floppy"),
  1014. __tr2qs("Temporary Files"),
  1015. __tr2qs("Network"),
  1016. __tr2qs("New Directory..."),
  1017. __tr2qs("Delete"),
  1018. __tr2qs("Thumbnail Previews"),
  1019. __tr2qs("Large Icons"),
  1020. __tr2qs("Small Icons"),
  1021. __tr2qs("Properties..."),
  1022. __tr2qs("&Automatic Preview"),
  1023. __tr2qs("&Preview"),
  1024. __tr2qs("&Location:"),
  1025. __tr2qs("&Filter:"),
  1026. __tr2qs("All Files"),
  1027. __tr2qs("&OK"),
  1028. __tr2qs("&Cancel")
  1029. }
  1030. #endif