1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/common/intl.cpp
3 // Purpose:     Internationalization and localisation for wxWidgets
4 // Author:      Vadim Zeitlin
5 // Modified by: Michael N. Filippov <michael@idisys.iae.nsk.su>
6 //              (2003/09/30 - PluralForms support)
7 // Created:     29/01/98
8 // RCS-ID:      $Id: intl.cpp 61340 2009-07-06 21:19:58Z VZ $
9 // Copyright:   (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
10 // Licence:     wxWindows licence
11 /////////////////////////////////////////////////////////////////////////////
12 
13 // ============================================================================
14 // declaration
15 // ============================================================================
16 
17 // ----------------------------------------------------------------------------
18 // headers
19 // ----------------------------------------------------------------------------
20 
21 // For compilers that support precompilation, includes "wx.h".
22 #include "wx/wxprec.h"
23 
24 #ifdef __BORLANDC__
25     #pragma hdrstop
26 #endif
27 
28 #ifdef __EMX__
29 // The following define is needed by Innotek's libc to
30 // make the definition of struct localeconv available.
31 #define __INTERNAL_DEFS
32 #endif
33 
34 #if wxUSE_INTL
35 
36 #ifndef WX_PRECOMP
37     #include "wx/dynarray.h"
38     #include "wx/string.h"
39     #include "wx/intl.h"
40     #include "wx/log.h"
41     #include "wx/utils.h"
42     #include "wx/app.h"
43     #include "wx/hashmap.h"
44     #include "wx/module.h"
45 #endif // WX_PRECOMP
46 
47 #ifndef __WXWINCE__
48     #include <locale.h>
49 #endif
50 
51 // standard headers
52 #include <ctype.h>
53 #include <stdlib.h>
54 #ifdef HAVE_LANGINFO_H
55     #include <langinfo.h>
56 #endif
57 
58 #ifdef __WIN32__
59     #include "wx/msw/private.h"
60 #elif defined(__UNIX_LIKE__)
61     #include "wx/fontmap.h"         // for CharsetToEncoding()
62 #endif
63 
64 #include "wx/file.h"
65 #include "wx/filename.h"
66 #include "wx/tokenzr.h"
67 #include "wx/fontmap.h"
68 #include "wx/encconv.h"
69 #include "wx/ptr_scpd.h"
70 #include "wx/apptrait.h"
71 #include "wx/stdpaths.h"
72 
73 #if defined(__WXMAC__)
74     #include  "wx/mac/private.h"  // includes mac headers
75 #endif
76 
77 #if defined(__DARWIN__)
78     #include "wx/mac/corefoundation/cfref.h"
79     #include <CoreFoundation/CFLocale.h>
80     #include "wx/mac/corefoundation/cfstring.h"
81 #endif
82 
83 // ----------------------------------------------------------------------------
84 // simple types
85 // ----------------------------------------------------------------------------
86 
87 // this should *not* be wxChar, this type must have exactly 8 bits!
88 typedef wxUint8 size_t8;
89 typedef wxUint32 size_t32;
90 
91 // ----------------------------------------------------------------------------
92 // constants
93 // ----------------------------------------------------------------------------
94 
95 // magic number identifying the .mo format file
96 const size_t32 MSGCATALOG_MAGIC    = 0x950412de;
97 const size_t32 MSGCATALOG_MAGIC_SW = 0xde120495;
98 
99 // the constants describing the format of lang_LANG locale string
100 static const size_t LEN_LANG = 2;
101 static const size_t LEN_SUBLANG = 2;
102 static const size_t LEN_FULL = LEN_LANG + 1 + LEN_SUBLANG; // 1 for '_'
103 
104 #define TRACE_I18N _T("i18n")
105 
106 // ----------------------------------------------------------------------------
107 // global functions
108 // ----------------------------------------------------------------------------
109 
110 #ifdef __WXDEBUG__
111 
112 // small class to suppress the translation erros until exit from current scope
113 class NoTransErr
114 {
115 public:
NoTransErr()116     NoTransErr() { ms_suppressCount++; }
~NoTransErr()117    ~NoTransErr() { ms_suppressCount--;  }
118 
Suppress()119    static bool Suppress() { return ms_suppressCount > 0; }
120 
121 private:
122    static size_t ms_suppressCount;
123 };
124 
125 size_t NoTransErr::ms_suppressCount = 0;
126 
127 #else // !Debug
128 
129 class NoTransErr
130 {
131 public:
NoTransErr()132     NoTransErr() { }
~NoTransErr()133    ~NoTransErr() { }
134 };
135 
136 #endif // Debug/!Debug
137 
138 static wxLocale *wxSetLocale(wxLocale *pLocale);
139 
140 // helper functions of GetSystemLanguage()
141 #ifdef __UNIX__
142 
143 // get just the language part
ExtractLang(const wxString & langFull)144 static inline wxString ExtractLang(const wxString& langFull)
145 {
146     return langFull.Left(LEN_LANG);
147 }
148 
149 // get everything else (including the leading '_')
ExtractNotLang(const wxString & langFull)150 static inline wxString ExtractNotLang(const wxString& langFull)
151 {
152     return langFull.Mid(LEN_LANG);
153 }
154 
155 #endif // __UNIX__
156 
157 
158 // ----------------------------------------------------------------------------
159 // Plural forms parser
160 // ----------------------------------------------------------------------------
161 
162 /*
163                                 Simplified Grammar
164 
165 Expression:
166     LogicalOrExpression '?' Expression ':' Expression
167     LogicalOrExpression
168 
169 LogicalOrExpression:
170     LogicalAndExpression "||" LogicalOrExpression   // to (a || b) || c
171     LogicalAndExpression
172 
173 LogicalAndExpression:
174     EqualityExpression "&&" LogicalAndExpression    // to (a && b) && c
175     EqualityExpression
176 
177 EqualityExpression:
178     RelationalExpression "==" RelationalExperession
179     RelationalExpression "!=" RelationalExperession
180     RelationalExpression
181 
182 RelationalExpression:
183     MultiplicativeExpression '>' MultiplicativeExpression
184     MultiplicativeExpression '<' MultiplicativeExpression
185     MultiplicativeExpression ">=" MultiplicativeExpression
186     MultiplicativeExpression "<=" MultiplicativeExpression
187     MultiplicativeExpression
188 
189 MultiplicativeExpression:
190     PmExpression '%' PmExpression
191     PmExpression
192 
193 PmExpression:
194     N
195     Number
196     '(' Expression ')'
197 */
198 
199 class wxPluralFormsToken
200 {
201 public:
202     enum Type
203     {
204         T_ERROR, T_EOF, T_NUMBER, T_N, T_PLURAL, T_NPLURALS, T_EQUAL, T_ASSIGN,
205         T_GREATER, T_GREATER_OR_EQUAL, T_LESS, T_LESS_OR_EQUAL,
206         T_REMINDER, T_NOT_EQUAL,
207         T_LOGICAL_AND, T_LOGICAL_OR, T_QUESTION, T_COLON, T_SEMICOLON,
208         T_LEFT_BRACKET, T_RIGHT_BRACKET
209     };
type() const210     Type type() const { return m_type; }
setType(Type type)211     void setType(Type type) { m_type = type; }
212     // for T_NUMBER only
213     typedef int Number;
number() const214     Number number() const { return m_number; }
setNumber(Number num)215     void setNumber(Number num) { m_number = num; }
216 private:
217     Type m_type;
218     Number m_number;
219 };
220 
221 
222 class wxPluralFormsScanner
223 {
224 public:
225     wxPluralFormsScanner(const char* s);
token() const226     const wxPluralFormsToken& token() const { return m_token; }
227     bool nextToken();  // returns false if error
228 private:
229     const char* m_s;
230     wxPluralFormsToken m_token;
231 };
232 
wxPluralFormsScanner(const char * s)233 wxPluralFormsScanner::wxPluralFormsScanner(const char* s) : m_s(s)
234 {
235     nextToken();
236 }
237 
nextToken()238 bool wxPluralFormsScanner::nextToken()
239 {
240     wxPluralFormsToken::Type type = wxPluralFormsToken::T_ERROR;
241     while (isspace((unsigned char) *m_s))
242     {
243         ++m_s;
244     }
245     if (*m_s == 0)
246     {
247         type = wxPluralFormsToken::T_EOF;
248     }
249     else if (isdigit((unsigned char) *m_s))
250     {
251         wxPluralFormsToken::Number number = *m_s++ - '0';
252         while (isdigit((unsigned char) *m_s))
253         {
254             number = number * 10 + (*m_s++ - '0');
255         }
256         m_token.setNumber(number);
257         type = wxPluralFormsToken::T_NUMBER;
258     }
259     else if (isalpha((unsigned char) *m_s))
260     {
261         const char* begin = m_s++;
262         while (isalnum((unsigned char) *m_s))
263         {
264             ++m_s;
265         }
266         size_t size = m_s - begin;
267         if (size == 1 && memcmp(begin, "n", size) == 0)
268         {
269             type = wxPluralFormsToken::T_N;
270         }
271         else if (size == 6 && memcmp(begin, "plural", size) == 0)
272         {
273             type = wxPluralFormsToken::T_PLURAL;
274         }
275         else if (size == 8 && memcmp(begin, "nplurals", size) == 0)
276         {
277             type = wxPluralFormsToken::T_NPLURALS;
278         }
279     }
280     else if (*m_s == '=')
281     {
282         ++m_s;
283         if (*m_s == '=')
284         {
285             ++m_s;
286             type = wxPluralFormsToken::T_EQUAL;
287         }
288         else
289         {
290             type = wxPluralFormsToken::T_ASSIGN;
291         }
292     }
293     else if (*m_s == '>')
294     {
295         ++m_s;
296         if (*m_s == '=')
297         {
298             ++m_s;
299             type = wxPluralFormsToken::T_GREATER_OR_EQUAL;
300         }
301         else
302         {
303             type = wxPluralFormsToken::T_GREATER;
304         }
305     }
306     else if (*m_s == '<')
307     {
308         ++m_s;
309         if (*m_s == '=')
310         {
311             ++m_s;
312             type = wxPluralFormsToken::T_LESS_OR_EQUAL;
313         }
314         else
315         {
316             type = wxPluralFormsToken::T_LESS;
317         }
318     }
319     else if (*m_s == '%')
320     {
321         ++m_s;
322         type = wxPluralFormsToken::T_REMINDER;
323     }
324     else if (*m_s == '!' && m_s[1] == '=')
325     {
326         m_s += 2;
327         type = wxPluralFormsToken::T_NOT_EQUAL;
328     }
329     else if (*m_s == '&' && m_s[1] == '&')
330     {
331         m_s += 2;
332         type = wxPluralFormsToken::T_LOGICAL_AND;
333     }
334     else if (*m_s == '|' && m_s[1] == '|')
335     {
336         m_s += 2;
337         type = wxPluralFormsToken::T_LOGICAL_OR;
338     }
339     else if (*m_s == '?')
340     {
341         ++m_s;
342         type = wxPluralFormsToken::T_QUESTION;
343     }
344     else if (*m_s == ':')
345     {
346         ++m_s;
347         type = wxPluralFormsToken::T_COLON;
348     } else if (*m_s == ';') {
349         ++m_s;
350         type = wxPluralFormsToken::T_SEMICOLON;
351     }
352     else if (*m_s == '(')
353     {
354         ++m_s;
355         type = wxPluralFormsToken::T_LEFT_BRACKET;
356     }
357     else if (*m_s == ')')
358     {
359         ++m_s;
360         type = wxPluralFormsToken::T_RIGHT_BRACKET;
361     }
362     m_token.setType(type);
363     return type != wxPluralFormsToken::T_ERROR;
364 }
365 
366 class wxPluralFormsNode;
367 
368 // NB: Can't use wxDEFINE_SCOPED_PTR_TYPE because wxPluralFormsNode is not
369 //     fully defined yet:
370 class wxPluralFormsNodePtr
371 {
372 public:
wxPluralFormsNodePtr(wxPluralFormsNode * p=NULL)373     wxPluralFormsNodePtr(wxPluralFormsNode *p = NULL) : m_p(p) {}
374     ~wxPluralFormsNodePtr();
operator *() const375     wxPluralFormsNode& operator*() const { return *m_p; }
operator ->() const376     wxPluralFormsNode* operator->() const { return m_p; }
get() const377     wxPluralFormsNode* get() const { return m_p; }
378     wxPluralFormsNode* release();
379     void reset(wxPluralFormsNode *p);
380 
381 private:
382     wxPluralFormsNode *m_p;
383 };
384 
385 class wxPluralFormsNode
386 {
387 public:
wxPluralFormsNode(const wxPluralFormsToken & token)388     wxPluralFormsNode(const wxPluralFormsToken& token) : m_token(token) {}
token() const389     const wxPluralFormsToken& token() const { return m_token; }
node(size_t i) const390     const wxPluralFormsNode* node(size_t i) const
391         { return m_nodes[i].get(); }
392     void setNode(size_t i, wxPluralFormsNode* n);
393     wxPluralFormsNode* releaseNode(size_t i);
394     wxPluralFormsToken::Number evaluate(wxPluralFormsToken::Number n) const;
395 
396 private:
397     wxPluralFormsToken m_token;
398     wxPluralFormsNodePtr m_nodes[3];
399 };
400 
~wxPluralFormsNodePtr()401 wxPluralFormsNodePtr::~wxPluralFormsNodePtr()
402 {
403     delete m_p;
404 }
release()405 wxPluralFormsNode* wxPluralFormsNodePtr::release()
406 {
407     wxPluralFormsNode *p = m_p;
408     m_p = NULL;
409     return p;
410 }
reset(wxPluralFormsNode * p)411 void wxPluralFormsNodePtr::reset(wxPluralFormsNode *p)
412 {
413     if (p != m_p)
414     {
415         delete m_p;
416         m_p = p;
417     }
418 }
419 
420 
setNode(size_t i,wxPluralFormsNode * n)421 void wxPluralFormsNode::setNode(size_t i, wxPluralFormsNode* n)
422 {
423     m_nodes[i].reset(n);
424 }
425 
releaseNode(size_t i)426 wxPluralFormsNode*  wxPluralFormsNode::releaseNode(size_t i)
427 {
428     return m_nodes[i].release();
429 }
430 
431 wxPluralFormsToken::Number
evaluate(wxPluralFormsToken::Number n) const432 wxPluralFormsNode::evaluate(wxPluralFormsToken::Number n) const
433 {
434     switch (token().type())
435     {
436         // leaf
437         case wxPluralFormsToken::T_NUMBER:
438             return token().number();
439         case wxPluralFormsToken::T_N:
440             return n;
441         // 2 args
442         case wxPluralFormsToken::T_EQUAL:
443             return node(0)->evaluate(n) == node(1)->evaluate(n);
444         case wxPluralFormsToken::T_NOT_EQUAL:
445             return node(0)->evaluate(n) != node(1)->evaluate(n);
446         case wxPluralFormsToken::T_GREATER:
447             return node(0)->evaluate(n) > node(1)->evaluate(n);
448         case wxPluralFormsToken::T_GREATER_OR_EQUAL:
449             return node(0)->evaluate(n) >= node(1)->evaluate(n);
450         case wxPluralFormsToken::T_LESS:
451             return node(0)->evaluate(n) < node(1)->evaluate(n);
452         case wxPluralFormsToken::T_LESS_OR_EQUAL:
453             return node(0)->evaluate(n) <= node(1)->evaluate(n);
454         case wxPluralFormsToken::T_REMINDER:
455             {
456                 wxPluralFormsToken::Number number = node(1)->evaluate(n);
457                 if (number != 0)
458                 {
459                     return node(0)->evaluate(n) % number;
460                 }
461                 else
462                 {
463                     return 0;
464                 }
465             }
466         case wxPluralFormsToken::T_LOGICAL_AND:
467             return node(0)->evaluate(n) && node(1)->evaluate(n);
468         case wxPluralFormsToken::T_LOGICAL_OR:
469             return node(0)->evaluate(n) || node(1)->evaluate(n);
470         // 3 args
471         case wxPluralFormsToken::T_QUESTION:
472             return node(0)->evaluate(n)
473                 ? node(1)->evaluate(n)
474                 : node(2)->evaluate(n);
475         default:
476             return 0;
477     }
478 }
479 
480 
481 class wxPluralFormsCalculator
482 {
483 public:
wxPluralFormsCalculator()484     wxPluralFormsCalculator() : m_nplurals(0), m_plural(0) {}
485 
486     // input: number, returns msgstr index
487     int evaluate(int n) const;
488 
489     // input: text after "Plural-Forms:" (e.g. "nplurals=2; plural=(n != 1);"),
490     // if s == 0, creates default handler
491     // returns 0 if error
492     static wxPluralFormsCalculator* make(const char* s = 0);
493 
~wxPluralFormsCalculator()494     ~wxPluralFormsCalculator() {}
495 
496     void  init(wxPluralFormsToken::Number nplurals, wxPluralFormsNode* plural);
497 
498 private:
499     wxPluralFormsToken::Number m_nplurals;
500     wxPluralFormsNodePtr m_plural;
501 };
502 
wxDEFINE_SCOPED_PTR_TYPE(wxPluralFormsCalculator)503 wxDEFINE_SCOPED_PTR_TYPE(wxPluralFormsCalculator)
504 
505 void wxPluralFormsCalculator::init(wxPluralFormsToken::Number nplurals,
506                                    wxPluralFormsNode* plural)
507 {
508     m_nplurals = nplurals;
509     m_plural.reset(plural);
510 }
511 
evaluate(int n) const512 int wxPluralFormsCalculator::evaluate(int n) const
513 {
514     if (m_plural.get() == 0)
515     {
516         return 0;
517     }
518     wxPluralFormsToken::Number number = m_plural->evaluate(n);
519     if (number < 0 || number > m_nplurals)
520     {
521         return 0;
522     }
523     return number;
524 }
525 
526 
527 class wxPluralFormsParser
528 {
529 public:
wxPluralFormsParser(wxPluralFormsScanner & scanner)530     wxPluralFormsParser(wxPluralFormsScanner& scanner) : m_scanner(scanner) {}
531     bool parse(wxPluralFormsCalculator& rCalculator);
532 
533 private:
534     wxPluralFormsNode* parsePlural();
535     // stops at T_SEMICOLON, returns 0 if error
536     wxPluralFormsScanner& m_scanner;
537     const wxPluralFormsToken& token() const;
538     bool nextToken();
539 
540     wxPluralFormsNode* expression();
541     wxPluralFormsNode* logicalOrExpression();
542     wxPluralFormsNode* logicalAndExpression();
543     wxPluralFormsNode* equalityExpression();
544     wxPluralFormsNode* multiplicativeExpression();
545     wxPluralFormsNode* relationalExpression();
546     wxPluralFormsNode* pmExpression();
547 };
548 
parse(wxPluralFormsCalculator & rCalculator)549 bool wxPluralFormsParser::parse(wxPluralFormsCalculator& rCalculator)
550 {
551     if (token().type() != wxPluralFormsToken::T_NPLURALS)
552         return false;
553     if (!nextToken())
554         return false;
555     if (token().type() != wxPluralFormsToken::T_ASSIGN)
556         return false;
557     if (!nextToken())
558         return false;
559     if (token().type() != wxPluralFormsToken::T_NUMBER)
560         return false;
561     wxPluralFormsToken::Number nplurals = token().number();
562     if (!nextToken())
563         return false;
564     if (token().type() != wxPluralFormsToken::T_SEMICOLON)
565         return false;
566     if (!nextToken())
567         return false;
568     if (token().type() != wxPluralFormsToken::T_PLURAL)
569         return false;
570     if (!nextToken())
571         return false;
572     if (token().type() != wxPluralFormsToken::T_ASSIGN)
573         return false;
574     if (!nextToken())
575         return false;
576     wxPluralFormsNode* plural = parsePlural();
577     if (plural == 0)
578         return false;
579     if (token().type() != wxPluralFormsToken::T_SEMICOLON)
580         return false;
581     if (!nextToken())
582         return false;
583     if (token().type() != wxPluralFormsToken::T_EOF)
584         return false;
585     rCalculator.init(nplurals, plural);
586     return true;
587 }
588 
parsePlural()589 wxPluralFormsNode* wxPluralFormsParser::parsePlural()
590 {
591     wxPluralFormsNode* p = expression();
592     if (p == NULL)
593     {
594         return NULL;
595     }
596     wxPluralFormsNodePtr n(p);
597     if (token().type() != wxPluralFormsToken::T_SEMICOLON)
598     {
599         return NULL;
600     }
601     return n.release();
602 }
603 
token() const604 const wxPluralFormsToken& wxPluralFormsParser::token() const
605 {
606     return m_scanner.token();
607 }
608 
nextToken()609 bool wxPluralFormsParser::nextToken()
610 {
611     if (!m_scanner.nextToken())
612         return false;
613     return true;
614 }
615 
expression()616 wxPluralFormsNode* wxPluralFormsParser::expression()
617 {
618     wxPluralFormsNode* p = logicalOrExpression();
619     if (p == NULL)
620         return NULL;
621     wxPluralFormsNodePtr n(p);
622     if (token().type() == wxPluralFormsToken::T_QUESTION)
623     {
624         wxPluralFormsNodePtr qn(new wxPluralFormsNode(token()));
625         if (!nextToken())
626         {
627             return 0;
628         }
629         p = expression();
630         if (p == 0)
631         {
632             return 0;
633         }
634         qn->setNode(1, p);
635         if (token().type() != wxPluralFormsToken::T_COLON)
636         {
637             return 0;
638         }
639         if (!nextToken())
640         {
641             return 0;
642         }
643         p = expression();
644         if (p == 0)
645         {
646             return 0;
647         }
648         qn->setNode(2, p);
649         qn->setNode(0, n.release());
650         return qn.release();
651     }
652     return n.release();
653 }
654 
logicalOrExpression()655 wxPluralFormsNode*wxPluralFormsParser::logicalOrExpression()
656 {
657     wxPluralFormsNode* p = logicalAndExpression();
658     if (p == NULL)
659         return NULL;
660     wxPluralFormsNodePtr ln(p);
661     if (token().type() == wxPluralFormsToken::T_LOGICAL_OR)
662     {
663         wxPluralFormsNodePtr un(new wxPluralFormsNode(token()));
664         if (!nextToken())
665         {
666             return 0;
667         }
668         p = logicalOrExpression();
669         if (p == 0)
670         {
671             return 0;
672         }
673         wxPluralFormsNodePtr rn(p);    // right
674         if (rn->token().type() == wxPluralFormsToken::T_LOGICAL_OR)
675         {
676             // see logicalAndExpression comment
677             un->setNode(0, ln.release());
678             un->setNode(1, rn->releaseNode(0));
679             rn->setNode(0, un.release());
680             return rn.release();
681         }
682 
683 
684         un->setNode(0, ln.release());
685         un->setNode(1, rn.release());
686         return un.release();
687     }
688     return ln.release();
689 }
690 
logicalAndExpression()691 wxPluralFormsNode* wxPluralFormsParser::logicalAndExpression()
692 {
693     wxPluralFormsNode* p = equalityExpression();
694     if (p == NULL)
695         return NULL;
696     wxPluralFormsNodePtr ln(p);   // left
697     if (token().type() == wxPluralFormsToken::T_LOGICAL_AND)
698     {
699         wxPluralFormsNodePtr un(new wxPluralFormsNode(token()));  // up
700         if (!nextToken())
701         {
702             return NULL;
703         }
704         p = logicalAndExpression();
705         if (p == 0)
706         {
707             return NULL;
708         }
709         wxPluralFormsNodePtr rn(p);    // right
710         if (rn->token().type() == wxPluralFormsToken::T_LOGICAL_AND)
711         {
712 // transform 1 && (2 && 3) -> (1 && 2) && 3
713 //     u                  r
714 // l       r     ->   u      3
715 //       2   3      l   2
716             un->setNode(0, ln.release());
717             un->setNode(1, rn->releaseNode(0));
718             rn->setNode(0, un.release());
719             return rn.release();
720         }
721 
722         un->setNode(0, ln.release());
723         un->setNode(1, rn.release());
724         return un.release();
725     }
726     return ln.release();
727 }
728 
equalityExpression()729 wxPluralFormsNode* wxPluralFormsParser::equalityExpression()
730 {
731     wxPluralFormsNode* p = relationalExpression();
732     if (p == NULL)
733         return NULL;
734     wxPluralFormsNodePtr n(p);
735     if (token().type() == wxPluralFormsToken::T_EQUAL
736         || token().type() == wxPluralFormsToken::T_NOT_EQUAL)
737     {
738         wxPluralFormsNodePtr qn(new wxPluralFormsNode(token()));
739         if (!nextToken())
740         {
741             return NULL;
742         }
743         p = relationalExpression();
744         if (p == NULL)
745         {
746             return NULL;
747         }
748         qn->setNode(1, p);
749         qn->setNode(0, n.release());
750         return qn.release();
751     }
752     return n.release();
753 }
754 
relationalExpression()755 wxPluralFormsNode* wxPluralFormsParser::relationalExpression()
756 {
757     wxPluralFormsNode* p = multiplicativeExpression();
758     if (p == NULL)
759         return NULL;
760     wxPluralFormsNodePtr n(p);
761     if (token().type() == wxPluralFormsToken::T_GREATER
762             || token().type() == wxPluralFormsToken::T_LESS
763             || token().type() == wxPluralFormsToken::T_GREATER_OR_EQUAL
764             || token().type() == wxPluralFormsToken::T_LESS_OR_EQUAL)
765     {
766         wxPluralFormsNodePtr qn(new wxPluralFormsNode(token()));
767         if (!nextToken())
768         {
769             return NULL;
770         }
771         p = multiplicativeExpression();
772         if (p == NULL)
773         {
774             return NULL;
775         }
776         qn->setNode(1, p);
777         qn->setNode(0, n.release());
778         return qn.release();
779     }
780     return n.release();
781 }
782 
multiplicativeExpression()783 wxPluralFormsNode* wxPluralFormsParser::multiplicativeExpression()
784 {
785     wxPluralFormsNode* p = pmExpression();
786     if (p == NULL)
787         return NULL;
788     wxPluralFormsNodePtr n(p);
789     if (token().type() == wxPluralFormsToken::T_REMINDER)
790     {
791         wxPluralFormsNodePtr qn(new wxPluralFormsNode(token()));
792         if (!nextToken())
793         {
794             return NULL;
795         }
796         p = pmExpression();
797         if (p == NULL)
798         {
799             return NULL;
800         }
801         qn->setNode(1, p);
802         qn->setNode(0, n.release());
803         return qn.release();
804     }
805     return n.release();
806 }
807 
pmExpression()808 wxPluralFormsNode* wxPluralFormsParser::pmExpression()
809 {
810     wxPluralFormsNodePtr n;
811     if (token().type() == wxPluralFormsToken::T_N
812         || token().type() == wxPluralFormsToken::T_NUMBER)
813     {
814         n.reset(new wxPluralFormsNode(token()));
815         if (!nextToken())
816         {
817             return NULL;
818         }
819     }
820     else if (token().type() == wxPluralFormsToken::T_LEFT_BRACKET) {
821         if (!nextToken())
822         {
823             return NULL;
824         }
825         wxPluralFormsNode* p = expression();
826         if (p == NULL)
827         {
828             return NULL;
829         }
830         n.reset(p);
831         if (token().type() != wxPluralFormsToken::T_RIGHT_BRACKET)
832         {
833             return NULL;
834         }
835         if (!nextToken())
836         {
837             return NULL;
838         }
839     }
840     else
841     {
842         return NULL;
843     }
844     return n.release();
845 }
846 
make(const char * s)847 wxPluralFormsCalculator* wxPluralFormsCalculator::make(const char* s)
848 {
849     wxPluralFormsCalculatorPtr calculator(new wxPluralFormsCalculator);
850     if (s != NULL)
851     {
852         wxPluralFormsScanner scanner(s);
853         wxPluralFormsParser p(scanner);
854         if (!p.parse(*calculator))
855         {
856             return NULL;
857         }
858     }
859     return calculator.release();
860 }
861 
862 
863 
864 
865 // ----------------------------------------------------------------------------
866 // wxMsgCatalogFile corresponds to one disk-file message catalog.
867 //
868 // This is a "low-level" class and is used only by wxMsgCatalog
869 // ----------------------------------------------------------------------------
870 
871 WX_DECLARE_EXPORTED_STRING_HASH_MAP(wxString, wxMessagesHash);
872 
873 class wxMsgCatalogFile
874 {
875 public:
876     // ctor & dtor
877     wxMsgCatalogFile();
878    ~wxMsgCatalogFile();
879 
880     // load the catalog from disk (szDirPrefix corresponds to language)
881     bool Load(const wxChar *szDirPrefix, const wxChar *szName,
882               wxPluralFormsCalculatorPtr& rPluralFormsCalculator);
883 
884     // fills the hash with string-translation pairs
885     void FillHash(wxMessagesHash& hash,
886                   const wxString& msgIdCharset,
887                   bool convertEncoding) const;
888 
889     // return the charset of the strings in this catalog or empty string if
890     // none/unknown
GetCharset() const891     wxString GetCharset() const { return m_charset; }
892 
893 private:
894     // this implementation is binary compatible with GNU gettext() version 0.10
895 
896     // an entry in the string table
897     struct wxMsgTableEntry
898     {
899       size_t32   nLen;           // length of the string
900       size_t32   ofsString;      // pointer to the string
901     };
902 
903     // header of a .mo file
904     struct wxMsgCatalogHeader
905     {
906       size_t32  magic,          // offset +00:  magic id
907                 revision,       //        +04:  revision
908                 numStrings;     //        +08:  number of strings in the file
909       size_t32  ofsOrigTable,   //        +0C:  start of original string table
910                 ofsTransTable;  //        +10:  start of translated string table
911       size_t32  nHashSize,      //        +14:  hash table size
912                 ofsHashTable;   //        +18:  offset of hash table start
913     };
914 
915     // all data is stored here, NULL if no data loaded
916     size_t8 *m_pData;
917 
918     // amount of memory pointed to by m_pData.
919     size_t32 m_nSize;
920 
921     // data description
922     size_t32          m_numStrings;   // number of strings in this domain
923     wxMsgTableEntry  *m_pOrigTable,   // pointer to original   strings
924                      *m_pTransTable;  //            translated
925 
926     wxString m_charset;               // from the message catalog header
927 
928 
929     // swap the 2 halves of 32 bit integer if needed
Swap(size_t32 ui) const930     size_t32 Swap(size_t32 ui) const
931     {
932           return m_bSwapped ? (ui << 24) | ((ui & 0xff00) << 8) |
933                               ((ui >> 8) & 0xff00) | (ui >> 24)
934                             : ui;
935     }
936 
StringAtOfs(wxMsgTableEntry * pTable,size_t32 n) const937     const char *StringAtOfs(wxMsgTableEntry *pTable, size_t32 n) const
938     {
939         const wxMsgTableEntry * const ent = pTable + n;
940 
941         // this check could fail for a corrupt message catalog
942         size_t32 ofsString = Swap(ent->ofsString);
943         if ( ofsString + Swap(ent->nLen) > m_nSize)
944         {
945             return NULL;
946         }
947 
948         return (const char *)(m_pData + ofsString);
949     }
950 
951     bool m_bSwapped;   // wrong endianness?
952 
953     DECLARE_NO_COPY_CLASS(wxMsgCatalogFile)
954 };
955 
956 
957 // ----------------------------------------------------------------------------
958 // wxMsgCatalog corresponds to one loaded message catalog.
959 //
960 // This is a "low-level" class and is used only by wxLocale (that's why
961 // it's designed to be stored in a linked list)
962 // ----------------------------------------------------------------------------
963 
964 class wxMsgCatalog
965 {
966 public:
967 #if !wxUSE_UNICODE
wxMsgCatalog()968     wxMsgCatalog() { m_conv = NULL; }
969     ~wxMsgCatalog();
970 #endif
971 
972     // load the catalog from disk (szDirPrefix corresponds to language)
973     bool Load(const wxChar *szDirPrefix, const wxChar *szName,
974               const wxChar *msgIdCharset = NULL, bool bConvertEncoding = false);
975 
976     // get name of the catalog
GetName() const977     wxString GetName() const { return m_name; }
978 
979     // get the translated string: returns NULL if not found
980     const wxChar *GetString(const wxChar *sz, size_t n = size_t(-1)) const;
981 
982     // public variable pointing to the next element in a linked list (or NULL)
983     wxMsgCatalog *m_pNext;
984 
985 private:
986     wxMessagesHash  m_messages; // all messages in the catalog
987     wxString        m_name;     // name of the domain
988 
989 #if !wxUSE_UNICODE
990     // the conversion corresponding to this catalog charset if we installed it
991     // as the global one
992     wxCSConv *m_conv;
993 #endif
994 
995     wxPluralFormsCalculatorPtr  m_pluralFormsCalculator;
996 };
997 
998 // ----------------------------------------------------------------------------
999 // global variables
1000 // ----------------------------------------------------------------------------
1001 
1002 // the list of the directories to search for message catalog files
1003 static wxArrayString gs_searchPrefixes;
1004 
1005 // ============================================================================
1006 // implementation
1007 // ============================================================================
1008 
1009 // ----------------------------------------------------------------------------
1010 // wxMsgCatalogFile class
1011 // ----------------------------------------------------------------------------
1012 
wxMsgCatalogFile()1013 wxMsgCatalogFile::wxMsgCatalogFile()
1014 {
1015     m_pData = NULL;
1016     m_nSize = 0;
1017 }
1018 
~wxMsgCatalogFile()1019 wxMsgCatalogFile::~wxMsgCatalogFile()
1020 {
1021     delete [] m_pData;
1022 }
1023 
1024 // return the directories to search for message catalogs under the given
1025 // prefix, separated by wxPATH_SEP
1026 static
GetMsgCatalogSubdirs(const wxChar * prefix,const wxChar * lang)1027 wxString GetMsgCatalogSubdirs(const wxChar *prefix, const wxChar *lang)
1028 {
1029     // Search first in Unix-standard prefix/lang/LC_MESSAGES, then in
1030     // prefix/lang and finally in just prefix.
1031     //
1032     // Note that we use LC_MESSAGES on all platforms and not just Unix, because
1033     // it doesn't cost much to look into one more directory and doing it this
1034     // way has two important benefits:
1035     // a) we don't break compatibility with wx-2.6 and older by stopping to
1036     //    look in a directory where the catalogs used to be and thus silently
1037     //    breaking apps after they are recompiled against the latest wx
1038     // b) it makes it possible to package app's support files in the same
1039     //    way on all target platforms
1040     wxString pathPrefix;
1041     pathPrefix << prefix << wxFILE_SEP_PATH << lang;
1042 
1043     wxString searchPath;
1044     searchPath.reserve(4*pathPrefix.length());
1045     searchPath << pathPrefix << wxFILE_SEP_PATH << wxT("LC_MESSAGES") << wxPATH_SEP
1046                << prefix << wxFILE_SEP_PATH << wxPATH_SEP
1047                << pathPrefix;
1048 
1049     return searchPath;
1050 }
1051 
1052 // construct the search path for the given language
GetFullSearchPath(const wxChar * lang)1053 static wxString GetFullSearchPath(const wxChar *lang)
1054 {
1055     // first take the entries explicitly added by the program
1056     wxArrayString paths;
1057     paths.reserve(gs_searchPrefixes.size() + 1);
1058     size_t n,
1059            count = gs_searchPrefixes.size();
1060     for ( n = 0; n < count; n++ )
1061     {
1062         paths.Add(GetMsgCatalogSubdirs(gs_searchPrefixes[n], lang));
1063     }
1064 
1065 
1066 #if wxUSE_STDPATHS
1067     // then look in the standard location
1068     const wxString stdp = wxStandardPaths::Get().
1069         GetLocalizedResourcesDir(lang, wxStandardPaths::ResourceCat_Messages);
1070 
1071     if ( paths.Index(stdp) == wxNOT_FOUND )
1072         paths.Add(stdp);
1073 #endif // wxUSE_STDPATHS
1074 
1075     // last look in default locations
1076 #ifdef __UNIX__
1077     // LC_PATH is a standard env var containing the search path for the .mo
1078     // files
1079     const wxChar *pszLcPath = wxGetenv(wxT("LC_PATH"));
1080     if ( pszLcPath )
1081     {
1082         const wxString lcp = GetMsgCatalogSubdirs(pszLcPath, lang);
1083         if ( paths.Index(lcp) == wxNOT_FOUND )
1084             paths.Add(lcp);
1085     }
1086 
1087     // also add the one from where wxWin was installed:
1088     wxString wxp = wxGetInstallPrefix();
1089     if ( !wxp.empty() )
1090     {
1091         wxp = GetMsgCatalogSubdirs(wxp + _T("/share/locale"), lang);
1092         if ( paths.Index(wxp) == wxNOT_FOUND )
1093             paths.Add(wxp);
1094     }
1095 #endif // __UNIX__
1096 
1097 
1098     // finally construct the full search path
1099     wxString searchPath;
1100     searchPath.reserve(500);
1101     count = paths.size();
1102     for ( n = 0; n < count; n++ )
1103     {
1104         searchPath += paths[n];
1105         if ( n != count - 1 )
1106             searchPath += wxPATH_SEP;
1107     }
1108 
1109     return searchPath;
1110 }
1111 
1112 // open disk file and read in it's contents
Load(const wxChar * szDirPrefix,const wxChar * szName,wxPluralFormsCalculatorPtr & rPluralFormsCalculator)1113 bool wxMsgCatalogFile::Load(const wxChar *szDirPrefix, const wxChar *szName,
1114                             wxPluralFormsCalculatorPtr& rPluralFormsCalculator)
1115 {
1116   wxString searchPath;
1117 
1118 #if wxUSE_FONTMAP
1119   // first look for the catalog for this language and the current locale:
1120   // notice that we don't use the system name for the locale as this would
1121   // force us to install catalogs in different locations depending on the
1122   // system but always use the canonical name
1123   wxFontEncoding encSys = wxLocale::GetSystemEncoding();
1124   if ( encSys != wxFONTENCODING_SYSTEM )
1125   {
1126     wxString fullname(szDirPrefix);
1127     fullname << _T('.') << wxFontMapperBase::GetEncodingName(encSys);
1128     searchPath << GetFullSearchPath(fullname) << wxPATH_SEP;
1129   }
1130 #endif // wxUSE_FONTMAP
1131 
1132 
1133   searchPath += GetFullSearchPath(szDirPrefix);
1134   const wxChar *sublocale = wxStrchr(szDirPrefix, wxT('_'));
1135   if ( sublocale )
1136   {
1137       // also add just base locale name: for things like "fr_BE" (belgium
1138       // french) we should use "fr" if no belgium specific message catalogs
1139       // exist
1140       searchPath << wxPATH_SEP
1141                  << GetFullSearchPath(wxString(szDirPrefix).
1142                                       Left((size_t)(sublocale - szDirPrefix)));
1143   }
1144 
1145   // don't give translation errors here because the wxstd catalog might
1146   // not yet be loaded (and it's normal)
1147   //
1148   // (we're using an object because we have several return paths)
1149 
1150   NoTransErr noTransErr;
1151   wxLogVerbose(_("looking for catalog '%s' in path '%s'."),
1152                szName, searchPath.c_str());
1153   wxLogTrace(TRACE_I18N, _T("Looking for \"%s.mo\" in \"%s\""),
1154              szName, searchPath.c_str());
1155 
1156   wxFileName fn(szName);
1157   fn.SetExt(_T("mo"));
1158   wxString strFullName;
1159   if ( !wxFindFileInPath(&strFullName, searchPath, fn.GetFullPath()) ) {
1160     wxLogVerbose(_("catalog file for domain '%s' not found."), szName);
1161     wxLogTrace(TRACE_I18N, _T("Catalog \"%s.mo\" not found"), szName);
1162     return false;
1163   }
1164 
1165   // open file
1166   wxLogVerbose(_("using catalog '%s' from '%s'."), szName, strFullName.c_str());
1167   wxLogTrace(TRACE_I18N, _T("Using catalog \"%s\"."), strFullName.c_str());
1168 
1169   wxFile fileMsg(strFullName);
1170   if ( !fileMsg.IsOpened() )
1171     return false;
1172 
1173   // get the file size (assume it is less than 4Gb...)
1174   wxFileOffset lenFile = fileMsg.Length();
1175   if ( lenFile == wxInvalidOffset )
1176     return false;
1177 
1178   size_t nSize = wx_truncate_cast(size_t, lenFile);
1179   wxASSERT_MSG( nSize == lenFile + size_t(0), _T("message catalog bigger than 4GB?") );
1180 
1181   // read the whole file in memory
1182   m_pData = new size_t8[nSize];
1183   if ( fileMsg.Read(m_pData, nSize) != lenFile ) {
1184     wxDELETEA(m_pData);
1185     return false;
1186   }
1187 
1188   // examine header
1189   bool bValid = nSize + (size_t)0 > sizeof(wxMsgCatalogHeader);
1190 
1191   wxMsgCatalogHeader *pHeader = (wxMsgCatalogHeader *)m_pData;
1192   if ( bValid ) {
1193     // we'll have to swap all the integers if it's true
1194     m_bSwapped = pHeader->magic == MSGCATALOG_MAGIC_SW;
1195 
1196     // check the magic number
1197     bValid = m_bSwapped || pHeader->magic == MSGCATALOG_MAGIC;
1198   }
1199 
1200   if ( !bValid ) {
1201     // it's either too short or has incorrect magic number
1202     wxLogWarning(_("'%s' is not a valid message catalog."), strFullName.c_str());
1203 
1204     wxDELETEA(m_pData);
1205     return false;
1206   }
1207 
1208   // initialize
1209   m_numStrings  = Swap(pHeader->numStrings);
1210   m_pOrigTable  = (wxMsgTableEntry *)(m_pData +
1211                    Swap(pHeader->ofsOrigTable));
1212   m_pTransTable = (wxMsgTableEntry *)(m_pData +
1213                    Swap(pHeader->ofsTransTable));
1214   m_nSize = (size_t32)nSize;
1215 
1216   // now parse catalog's header and try to extract catalog charset and
1217   // plural forms formula from it:
1218 
1219   const char* headerData = StringAtOfs(m_pOrigTable, 0);
1220   if (headerData && headerData[0] == 0)
1221   {
1222       // Extract the charset:
1223       wxString header = wxString::FromAscii(StringAtOfs(m_pTransTable, 0));
1224       int begin = header.Find(wxT("Content-Type: text/plain; charset="));
1225       if (begin != wxNOT_FOUND)
1226       {
1227           begin += 34; //strlen("Content-Type: text/plain; charset=")
1228           size_t end = header.find('\n', begin);
1229           if (end != size_t(-1))
1230           {
1231               m_charset.assign(header, begin, end - begin);
1232               if (m_charset == wxT("CHARSET"))
1233               {
1234                   // "CHARSET" is not valid charset, but lazy translator
1235                   m_charset.Clear();
1236               }
1237           }
1238       }
1239       // else: incorrectly filled Content-Type header
1240 
1241       // Extract plural forms:
1242       begin = header.Find(wxT("Plural-Forms:"));
1243       if (begin != wxNOT_FOUND)
1244       {
1245           begin += 13;
1246           size_t end = header.find('\n', begin);
1247           if (end != size_t(-1))
1248           {
1249               wxString pfs(header, begin, end - begin);
1250               wxPluralFormsCalculator* pCalculator = wxPluralFormsCalculator
1251                   ::make(pfs.ToAscii());
1252               if (pCalculator != 0)
1253               {
1254                   rPluralFormsCalculator.reset(pCalculator);
1255               }
1256               else
1257               {
1258                    wxLogVerbose(_("Cannot parse Plural-Forms:'%s'"), pfs.c_str());
1259               }
1260           }
1261       }
1262       if (rPluralFormsCalculator.get() == NULL)
1263       {
1264           rPluralFormsCalculator.reset(wxPluralFormsCalculator::make());
1265       }
1266   }
1267 
1268   // everything is fine
1269   return true;
1270 }
1271 
FillHash(wxMessagesHash & hash,const wxString & msgIdCharset,bool convertEncoding) const1272 void wxMsgCatalogFile::FillHash(wxMessagesHash& hash,
1273                                 const wxString& msgIdCharset,
1274                                 bool convertEncoding) const
1275 {
1276 #if wxUSE_UNICODE
1277     // this parameter doesn't make sense, we always must convert encoding in
1278     // Unicode build
1279     convertEncoding = true;
1280 #elif wxUSE_FONTMAP
1281     if ( convertEncoding )
1282     {
1283         // determine if we need any conversion at all
1284         wxFontEncoding encCat = wxFontMapperBase::GetEncodingFromName(m_charset);
1285         if ( encCat == wxLocale::GetSystemEncoding() )
1286         {
1287             // no need to convert
1288             convertEncoding = false;
1289         }
1290     }
1291 #endif // wxUSE_UNICODE/wxUSE_FONTMAP
1292 
1293 #if wxUSE_WCHAR_T
1294     // conversion to use to convert catalog strings to the GUI encoding
1295     wxMBConv *inputConv,
1296              *inputConvPtr = NULL; // same as inputConv but safely deleteable
1297     if ( convertEncoding && !m_charset.empty() )
1298     {
1299         inputConvPtr =
1300         inputConv = new wxCSConv(m_charset);
1301     }
1302     else // no need or not possible to convert the encoding
1303     {
1304 #if wxUSE_UNICODE
1305         // we must somehow convert the narrow strings in the message catalog to
1306         // wide strings, so use the default conversion if we have no charset
1307         inputConv = wxConvCurrent;
1308 #else // !wxUSE_UNICODE
1309         inputConv = NULL;
1310 #endif // wxUSE_UNICODE/!wxUSE_UNICODE
1311     }
1312 
1313     // conversion to apply to msgid strings before looking them up: we only
1314     // need it if the msgids are neither in 7 bit ASCII nor in the same
1315     // encoding as the catalog
1316     wxCSConv *sourceConv = msgIdCharset.empty() || (msgIdCharset == m_charset)
1317                             ? NULL
1318                             : new wxCSConv(msgIdCharset);
1319 
1320 #elif wxUSE_FONTMAP
1321     wxASSERT_MSG( msgIdCharset.empty(),
1322                   _T("non-ASCII msgid languages only supported if wxUSE_WCHAR_T=1") );
1323 
1324     wxEncodingConverter converter;
1325     if ( convertEncoding )
1326     {
1327         wxFontEncoding targetEnc = wxFONTENCODING_SYSTEM;
1328         wxFontEncoding enc = wxFontMapperBase::Get()->CharsetToEncoding(m_charset, false);
1329         if ( enc == wxFONTENCODING_SYSTEM )
1330         {
1331             convertEncoding = false; // unknown encoding
1332         }
1333         else
1334         {
1335             targetEnc = wxLocale::GetSystemEncoding();
1336             if (targetEnc == wxFONTENCODING_SYSTEM)
1337             {
1338                 wxFontEncodingArray a = wxEncodingConverter::GetPlatformEquivalents(enc);
1339                 if (a[0] == enc)
1340                     // no conversion needed, locale uses native encoding
1341                     convertEncoding = false;
1342                 if (a.GetCount() == 0)
1343                     // we don't know common equiv. under this platform
1344                     convertEncoding = false;
1345                 targetEnc = a[0];
1346             }
1347         }
1348 
1349         if ( convertEncoding )
1350         {
1351             converter.Init(enc, targetEnc);
1352         }
1353     }
1354 #endif // wxUSE_WCHAR_T/!wxUSE_WCHAR_T
1355     (void)convertEncoding; // get rid of warnings about unused parameter
1356 
1357     for (size_t32 i = 0; i < m_numStrings; i++)
1358     {
1359         const char *data = StringAtOfs(m_pOrigTable, i);
1360 
1361         wxString msgid;
1362 #if wxUSE_UNICODE
1363         msgid = wxString(data, *inputConv);
1364 #else // ASCII
1365         #if wxUSE_WCHAR_T
1366             if ( inputConv && sourceConv )
1367                 msgid = wxString(inputConv->cMB2WC(data), *sourceConv);
1368             else
1369         #endif
1370                 msgid = data;
1371 #endif // wxUSE_UNICODE
1372 
1373         data = StringAtOfs(m_pTransTable, i);
1374         size_t length = Swap(m_pTransTable[i].nLen);
1375         size_t offset = 0;
1376         size_t index = 0;
1377         while (offset < length)
1378         {
1379             const char * const str = data + offset;
1380 
1381             wxString msgstr;
1382 #if wxUSE_UNICODE
1383             msgstr = wxString(str, *inputConv);
1384 #elif wxUSE_WCHAR_T
1385             if ( inputConv )
1386                 msgstr = wxString(inputConv->cMB2WC(str), *wxConvUI);
1387             else
1388                 msgstr = str;
1389 #else // !wxUSE_WCHAR_T
1390         #if wxUSE_FONTMAP
1391             if ( convertEncoding )
1392                 msgstr = wxString(converter.Convert(str));
1393             else
1394         #endif
1395                 msgstr = str;
1396 #endif // wxUSE_WCHAR_T/!wxUSE_WCHAR_T
1397 
1398             if ( !msgstr.empty() )
1399             {
1400                 hash[index == 0 ? msgid : msgid + wxChar(index)] = msgstr;
1401             }
1402 
1403             // skip this string
1404             offset += strlen(str) + 1;
1405             ++index;
1406         }
1407     }
1408 
1409 #if wxUSE_WCHAR_T
1410     delete sourceConv;
1411     delete inputConvPtr;
1412 #endif // wxUSE_WCHAR_T
1413 }
1414 
1415 
1416 // ----------------------------------------------------------------------------
1417 // wxMsgCatalog class
1418 // ----------------------------------------------------------------------------
1419 
1420 #if !wxUSE_UNICODE
~wxMsgCatalog()1421 wxMsgCatalog::~wxMsgCatalog()
1422 {
1423     if ( m_conv )
1424     {
1425         if ( wxConvUI == m_conv )
1426         {
1427             // we only change wxConvUI if it points to wxConvLocal so we reset
1428             // it back to it too
1429             wxConvUI = &wxConvLocal;
1430         }
1431 
1432         delete m_conv;
1433     }
1434 }
1435 #endif // !wxUSE_UNICODE
1436 
Load(const wxChar * szDirPrefix,const wxChar * szName,const wxChar * msgIdCharset,bool bConvertEncoding)1437 bool wxMsgCatalog::Load(const wxChar *szDirPrefix, const wxChar *szName,
1438                         const wxChar *msgIdCharset, bool bConvertEncoding)
1439 {
1440     wxMsgCatalogFile file;
1441 
1442     m_name = szName;
1443 
1444     if ( !file.Load(szDirPrefix, szName, m_pluralFormsCalculator) )
1445         return false;
1446 
1447     file.FillHash(m_messages, msgIdCharset, bConvertEncoding);
1448 
1449 #if !wxUSE_UNICODE && wxUSE_WCHAR_T
1450     // we should use a conversion compatible with the message catalog encoding
1451     // in the GUI if we don't convert the strings to the current conversion but
1452     // as the encoding is global, only change it once, otherwise we could get
1453     // into trouble if we use several message catalogs with different encodings
1454     //
1455     // this is, of course, a hack but it at least allows the program to use
1456     // message catalogs in any encodings without asking the user to change his
1457     // locale
1458     if ( !bConvertEncoding &&
1459             !file.GetCharset().empty() &&
1460                 wxConvUI == &wxConvLocal )
1461     {
1462         wxConvUI =
1463         m_conv = new wxCSConv(file.GetCharset());
1464     }
1465 #endif // !wxUSE_UNICODE && wxUSE_WCHAR_T
1466 
1467     return true;
1468 }
1469 
GetString(const wxChar * sz,size_t n) const1470 const wxChar *wxMsgCatalog::GetString(const wxChar *sz, size_t n) const
1471 {
1472     int index = 0;
1473     if (n != size_t(-1))
1474     {
1475         index = m_pluralFormsCalculator->evaluate(n);
1476     }
1477     wxMessagesHash::const_iterator i;
1478     if (index != 0)
1479     {
1480         i = m_messages.find(wxString(sz) + wxChar(index));   // plural
1481     }
1482     else
1483     {
1484         i = m_messages.find(sz);
1485     }
1486 
1487     if ( i != m_messages.end() )
1488     {
1489         return i->second.c_str();
1490     }
1491     else
1492         return NULL;
1493 }
1494 
1495 // ----------------------------------------------------------------------------
1496 // wxLocale
1497 // ----------------------------------------------------------------------------
1498 
1499 #include "wx/arrimpl.cpp"
1500 WX_DECLARE_EXPORTED_OBJARRAY(wxLanguageInfo, wxLanguageInfoArray);
1501 WX_DEFINE_OBJARRAY(wxLanguageInfoArray)
1502 
1503 wxLanguageInfoArray *wxLocale::ms_languagesDB = NULL;
1504 
CreateLanguagesDB()1505 /*static*/ void wxLocale::CreateLanguagesDB()
1506 {
1507     if (ms_languagesDB == NULL)
1508     {
1509         ms_languagesDB = new wxLanguageInfoArray;
1510         InitLanguagesDB();
1511     }
1512 }
1513 
DestroyLanguagesDB()1514 /*static*/ void wxLocale::DestroyLanguagesDB()
1515 {
1516     delete ms_languagesDB;
1517     ms_languagesDB = NULL;
1518 }
1519 
1520 
DoCommonInit()1521 void wxLocale::DoCommonInit()
1522 {
1523   m_pszOldLocale = NULL;
1524 
1525   m_pOldLocale = wxSetLocale(this);
1526 
1527   m_pMsgCat = NULL;
1528   m_language = wxLANGUAGE_UNKNOWN;
1529   m_initialized = false;
1530 }
1531 
1532 // NB: this function has (desired) side effect of changing current locale
Init(const wxChar * szName,const wxChar * szShort,const wxChar * szLocale,bool bLoadDefault,bool bConvertEncoding)1533 bool wxLocale::Init(const wxChar *szName,
1534                     const wxChar *szShort,
1535                     const wxChar *szLocale,
1536                     bool        bLoadDefault,
1537                     bool        bConvertEncoding)
1538 {
1539   wxASSERT_MSG( !m_initialized,
1540                 _T("you can't call wxLocale::Init more than once") );
1541 
1542   m_initialized = true;
1543   m_strLocale = szName;
1544   m_strShort = szShort;
1545   m_bConvertEncoding = bConvertEncoding;
1546   m_language = wxLANGUAGE_UNKNOWN;
1547 
1548   // change current locale (default: same as long name)
1549   if ( szLocale == NULL )
1550   {
1551     // the argument to setlocale()
1552     szLocale = szShort;
1553 
1554     wxCHECK_MSG( szLocale, false, _T("no locale to set in wxLocale::Init()") );
1555   }
1556 
1557 #ifdef __WXWINCE__
1558   // FIXME: I'm guessing here
1559   wxChar localeName[256];
1560   int ret = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SLANGUAGE, localeName,
1561       256);
1562   if (ret != 0)
1563   {
1564     m_pszOldLocale = wxStrdup(localeName);
1565   }
1566   else
1567     m_pszOldLocale = NULL;
1568 
1569   // TODO: how to find languageId
1570   // SetLocaleInfo(languageId, SORT_DEFAULT, localeName);
1571 #else
1572   wxMB2WXbuf oldLocale = wxSetlocale(LC_ALL, szLocale);
1573   if ( oldLocale )
1574       m_pszOldLocale = wxStrdup(oldLocale);
1575   else
1576       m_pszOldLocale = NULL;
1577 #endif
1578 
1579   if ( m_pszOldLocale == NULL )
1580     wxLogError(_("locale '%s' can not be set."), szLocale);
1581 
1582   // the short name will be used to look for catalog files as well,
1583   // so we need something here
1584   if ( m_strShort.empty() ) {
1585     // FIXME I don't know how these 2 letter abbreviations are formed,
1586     //       this wild guess is surely wrong
1587     if ( szLocale && szLocale[0] )
1588     {
1589         m_strShort += (wxChar)wxTolower(szLocale[0]);
1590         if ( szLocale[1] )
1591             m_strShort += (wxChar)wxTolower(szLocale[1]);
1592     }
1593   }
1594 
1595   // load the default catalog with wxWidgets standard messages
1596   m_pMsgCat = NULL;
1597   bool bOk = true;
1598   if ( bLoadDefault )
1599   {
1600     bOk = AddCatalog(wxT("wxstd" wxSTRINGIZE(wxMAJOR_VERSION) wxSTRINGIZE(wxMINOR_VERSION)));
1601 
1602     // there may be a catalog with toolkit specific overrides, it is not
1603     // an error if this does not exist
1604     if ( bOk )
1605     {
1606       wxString port(wxPlatformInfo::Get().GetPortIdName());
1607       if ( !port.empty() )
1608       {
1609         AddCatalog(port.BeforeFirst(wxT('/')).MakeLower());
1610       }
1611     }
1612   }
1613 
1614   return bOk;
1615 }
1616 
1617 
1618 #if defined(__UNIX__) && wxUSE_UNICODE && !defined(__WXMAC__)
wxSetlocaleTryUTF(int c,const wxChar * lc)1619 static wxWCharBuffer wxSetlocaleTryUTF(int c, const wxChar *lc)
1620 {
1621     wxMB2WXbuf l = wxSetlocale(c, lc);
1622     if ( !l && lc && lc[0] != 0 )
1623     {
1624         wxString buf(lc);
1625         wxString buf2;
1626         buf2 = buf + wxT(".UTF-8");
1627         l = wxSetlocale(c, buf2.c_str());
1628         if ( !l )
1629         {
1630             buf2 = buf + wxT(".utf-8");
1631             l = wxSetlocale(c, buf2.c_str());
1632         }
1633         if ( !l )
1634         {
1635             buf2 = buf + wxT(".UTF8");
1636             l = wxSetlocale(c, buf2.c_str());
1637         }
1638         if ( !l )
1639         {
1640             buf2 = buf + wxT(".utf8");
1641             l = wxSetlocale(c, buf2.c_str());
1642         }
1643     }
1644     return l;
1645 }
1646 #else
1647 #define wxSetlocaleTryUTF(c, lc)  wxSetlocale(c, lc)
1648 #endif
1649 
Init(int language,int flags)1650 bool wxLocale::Init(int language, int flags)
1651 {
1652     int lang = language;
1653     if (lang == wxLANGUAGE_DEFAULT)
1654     {
1655         // auto detect the language
1656         lang = GetSystemLanguage();
1657     }
1658 
1659     // We failed to detect system language, so we will use English:
1660     if (lang == wxLANGUAGE_UNKNOWN)
1661     {
1662        return false;
1663     }
1664 
1665     const wxLanguageInfo *info = GetLanguageInfo(lang);
1666 
1667     // Unknown language:
1668     if (info == NULL)
1669     {
1670         wxLogError(wxT("Unknown language %i."), lang);
1671         return false;
1672     }
1673 
1674     wxString name = info->Description;
1675     wxString canonical = info->CanonicalName;
1676     wxString locale;
1677 
1678     // Set the locale:
1679 #if defined(__OS2__)
1680     wxMB2WXbuf retloc = wxSetlocale(LC_ALL , wxEmptyString);
1681 #elif defined(__UNIX__) && !defined(__WXMAC__)
1682     if (language != wxLANGUAGE_DEFAULT)
1683         locale = info->CanonicalName;
1684 
1685     wxMB2WXbuf retloc = wxSetlocaleTryUTF(LC_ALL, locale);
1686 
1687     const wxString langOnly = locale.Left(2);
1688     if ( !retloc )
1689     {
1690         // Some C libraries don't like xx_YY form and require xx only
1691         retloc = wxSetlocaleTryUTF(LC_ALL, langOnly);
1692     }
1693 
1694 #if wxUSE_FONTMAP
1695     // some systems (e.g. FreeBSD and HP-UX) don't have xx_YY aliases but
1696     // require the full xx_YY.encoding form, so try using UTF-8 because this is
1697     // the only thing we can do generically
1698     //
1699     // TODO: add encodings applicable to each language to the lang DB and try
1700     //       them all in turn here
1701     if ( !retloc )
1702     {
1703         const wxChar **names =
1704             wxFontMapperBase::GetAllEncodingNames(wxFONTENCODING_UTF8);
1705         while ( *names )
1706         {
1707             retloc = wxSetlocale(LC_ALL, locale + _T('.') + *names++);
1708             if ( retloc )
1709                 break;
1710         }
1711     }
1712 #endif // wxUSE_FONTMAP
1713 
1714     if ( !retloc )
1715     {
1716         // Some C libraries (namely glibc) still use old ISO 639,
1717         // so will translate the abbrev for them
1718         wxString localeAlt;
1719         if ( langOnly == wxT("he") )
1720             localeAlt = wxT("iw") + locale.Mid(3);
1721         else if ( langOnly == wxT("id") )
1722             localeAlt = wxT("in") + locale.Mid(3);
1723         else if ( langOnly == wxT("yi") )
1724             localeAlt = wxT("ji") + locale.Mid(3);
1725         else if ( langOnly == wxT("nb") )
1726             localeAlt = wxT("no_NO");
1727         else if ( langOnly == wxT("nn") )
1728             localeAlt = wxT("no_NY");
1729 
1730         if ( !localeAlt.empty() )
1731         {
1732             retloc = wxSetlocaleTryUTF(LC_ALL, localeAlt);
1733             if ( !retloc )
1734                 retloc = wxSetlocaleTryUTF(LC_ALL, localeAlt.Left(2));
1735         }
1736     }
1737 
1738     if ( !retloc )
1739     {
1740         wxLogError(wxT("Cannot set locale to '%s'."), locale.c_str());
1741         return false;
1742     }
1743 
1744 #ifdef __AIX__
1745     // at least in AIX 5.2 libc is buggy and the string returned from setlocale(LC_ALL)
1746     // can't be passed back to it because it returns 6 strings (one for each locale
1747     // category), i.e. for C locale we get back "C C C C C C"
1748     //
1749     // this contradicts IBM own docs but this is not of much help, so just work around
1750     // it in the crudest possible manner
1751     wxChar *p = wxStrchr((wxChar *)retloc, _T(' '));
1752     if ( p )
1753         *p = _T('\0');
1754 #endif // __AIX__
1755 
1756 #elif defined(__WIN32__)
1757 
1758     #if wxUSE_UNICODE && (defined(__VISUALC__) || defined(__MINGW32__))
1759         // NB: setlocale() from msvcrt.dll (used by VC++ and Mingw)
1760         //     can't set locale to language that can only be written using
1761         //     Unicode.  Therefore wxSetlocale call failed, but we don't want
1762         //     to report it as an error -- so that at least message catalogs
1763         //     can be used. Watch for code marked with
1764         //     #ifdef SETLOCALE_FAILS_ON_UNICODE_LANGS bellow.
1765         #define SETLOCALE_FAILS_ON_UNICODE_LANGS
1766     #endif
1767 
1768 #if !wxUSE_UNICODE
1769     const
1770 #endif
1771     wxMB2WXbuf retloc = wxT("C");
1772     if (language != wxLANGUAGE_DEFAULT)
1773     {
1774         if (info->WinLang == 0)
1775         {
1776             wxLogWarning(wxT("Locale '%s' not supported by OS."), name.c_str());
1777             // retloc already set to "C"
1778         }
1779         else
1780         {
1781             int codepage
1782                          #ifdef SETLOCALE_FAILS_ON_UNICODE_LANGS
1783                          = -1
1784                          #endif
1785                          ;
1786             wxUint32 lcid = MAKELCID(MAKELANGID(info->WinLang, info->WinSublang),
1787                                      SORT_DEFAULT);
1788             // FIXME
1789 #ifndef __WXWINCE__
1790             SetThreadLocale(lcid);
1791 #endif
1792             // NB: we must translate LCID to CRT's setlocale string ourselves,
1793             //     because SetThreadLocale does not modify change the
1794             //     interpretation of setlocale(LC_ALL, "") call:
1795             wxChar buffer[256];
1796             buffer[0] = wxT('\0');
1797             GetLocaleInfo(lcid, LOCALE_SENGLANGUAGE, buffer, 256);
1798             locale << buffer;
1799             if (GetLocaleInfo(lcid, LOCALE_SENGCOUNTRY, buffer, 256) > 0)
1800                 locale << wxT("_") << buffer;
1801             if (GetLocaleInfo(lcid, LOCALE_IDEFAULTANSICODEPAGE, buffer, 256) > 0)
1802             {
1803                 codepage = wxAtoi(buffer);
1804                 if (codepage != 0)
1805                     locale << wxT(".") << buffer;
1806             }
1807             if (locale.empty())
1808             {
1809                 wxLogLastError(wxT("SetThreadLocale"));
1810                 wxLogError(wxT("Cannot set locale to language %s."), name.c_str());
1811                 return false;
1812             }
1813             else
1814             {
1815             // FIXME
1816 #ifndef __WXWINCE__
1817                 retloc = wxSetlocale(LC_ALL, locale);
1818 #endif
1819 #ifdef SETLOCALE_FAILS_ON_UNICODE_LANGS
1820                 if (codepage == 0 && (const wxChar*)retloc == NULL)
1821                 {
1822                     retloc = wxT("C");
1823                 }
1824 #endif
1825             }
1826         }
1827     }
1828     else
1829     {
1830             // FIXME
1831 #ifndef __WXWINCE__
1832         retloc = wxSetlocale(LC_ALL, wxEmptyString);
1833 #else
1834         retloc = NULL;
1835 #endif
1836 #ifdef SETLOCALE_FAILS_ON_UNICODE_LANGS
1837         if ((const wxChar*)retloc == NULL)
1838         {
1839             wxChar buffer[16];
1840             if (GetLocaleInfo(LOCALE_USER_DEFAULT,
1841                               LOCALE_IDEFAULTANSICODEPAGE, buffer, 16) > 0 &&
1842                  wxStrcmp(buffer, wxT("0")) == 0)
1843             {
1844                 retloc = wxT("C");
1845             }
1846         }
1847 #endif
1848     }
1849 
1850     if ( !retloc )
1851     {
1852         wxLogError(wxT("Cannot set locale to language %s."), name.c_str());
1853         return false;
1854     }
1855 #elif defined(__WXMAC__)
1856     if (lang == wxLANGUAGE_DEFAULT)
1857         locale = wxEmptyString;
1858     else
1859         locale = info->CanonicalName;
1860 
1861     wxMB2WXbuf retloc = wxSetlocale(LC_ALL, locale);
1862 
1863     if ( !retloc )
1864     {
1865         // Some C libraries don't like xx_YY form and require xx only
1866         retloc = wxSetlocale(LC_ALL, locale.Mid(0,2));
1867     }
1868     if ( !retloc )
1869     {
1870         wxLogError(wxT("Cannot set locale to '%s'."), locale.c_str());
1871         return false;
1872     }
1873 #else
1874     wxUnusedVar(flags);
1875     return false;
1876     #define WX_NO_LOCALE_SUPPORT
1877 #endif
1878 
1879 #ifndef WX_NO_LOCALE_SUPPORT
1880     wxChar *szLocale = retloc ? wxStrdup(retloc) : NULL;
1881     bool ret = Init(name, canonical, szLocale,
1882                     (flags & wxLOCALE_LOAD_DEFAULT) != 0,
1883                     (flags & wxLOCALE_CONV_ENCODING) != 0);
1884     free(szLocale);
1885 
1886     if (IsOk()) // setlocale() succeeded
1887         m_language = lang;
1888 
1889     return ret;
1890 #endif // !WX_NO_LOCALE_SUPPORT
1891 }
1892 
1893 
1894 
AddCatalogLookupPathPrefix(const wxString & prefix)1895 void wxLocale::AddCatalogLookupPathPrefix(const wxString& prefix)
1896 {
1897     if ( gs_searchPrefixes.Index(prefix) == wxNOT_FOUND )
1898     {
1899         gs_searchPrefixes.Add(prefix);
1900     }
1901     //else: already have it
1902 }
1903 
GetSystemLanguage()1904 /*static*/ int wxLocale::GetSystemLanguage()
1905 {
1906     CreateLanguagesDB();
1907 
1908     // init i to avoid compiler warning
1909     size_t i = 0,
1910            count = ms_languagesDB->GetCount();
1911 
1912 #if defined(__UNIX__) && !defined(__WXMAC__)
1913     // first get the string identifying the language from the environment
1914     wxString langFull;
1915     if (!wxGetEnv(wxT("LC_ALL"), &langFull) &&
1916         !wxGetEnv(wxT("LC_MESSAGES"), &langFull) &&
1917         !wxGetEnv(wxT("LANG"), &langFull))
1918     {
1919         // no language specified, treat it as English
1920         return wxLANGUAGE_ENGLISH_US;
1921     }
1922 
1923     if ( langFull == _T("C") || langFull == _T("POSIX") )
1924     {
1925         // default C locale is English too
1926         return wxLANGUAGE_ENGLISH_US;
1927     }
1928 
1929     // the language string has the following form
1930     //
1931     //      lang[_LANG][.encoding][@modifier]
1932     //
1933     // (see environ(5) in the Open Unix specification)
1934     //
1935     // where lang is the primary language, LANG is a sublang/territory,
1936     // encoding is the charset to use and modifier "allows the user to select
1937     // a specific instance of localization data within a single category"
1938     //
1939     // for example, the following strings are valid:
1940     //      fr
1941     //      fr_FR
1942     //      de_DE.iso88591
1943     //      de_DE@euro
1944     //      de_DE.iso88591@euro
1945 
1946     // for now we don't use the encoding, although we probably should (doing
1947     // translations of the msg catalogs on the fly as required) (TODO)
1948     //
1949     // we need the modified for languages like Valencian: ca_ES@valencia
1950     // though, remember it
1951     wxString modifier;
1952     size_t posModifier = langFull.find_first_of(_T("@"));
1953     if ( posModifier != wxString::npos )
1954         modifier = langFull.Mid(posModifier);
1955 
1956     size_t posEndLang = langFull.find_first_of(_T("@."));
1957     if ( posEndLang != wxString::npos )
1958     {
1959         langFull.Truncate(posEndLang);
1960     }
1961 
1962     // in addition to the format above, we also can have full language names
1963     // in LANG env var - for example, SuSE is known to use LANG="german" - so
1964     // check for this
1965 
1966     // do we have just the language (or sublang too)?
1967     bool justLang = langFull.length() == LEN_LANG;
1968     if ( justLang ||
1969          (langFull.length() == LEN_FULL && langFull[LEN_LANG] == wxT('_')) )
1970     {
1971         // 0. Make sure the lang is according to latest ISO 639
1972         //    (this is necessary because glibc uses iw and in instead
1973         //    of he and id respectively).
1974 
1975         // the language itself (second part is the dialect/sublang)
1976         wxString langOrig = ExtractLang(langFull);
1977 
1978         wxString lang;
1979         if ( langOrig == wxT("iw"))
1980             lang = _T("he");
1981         else if (langOrig == wxT("in"))
1982             lang = wxT("id");
1983         else if (langOrig == wxT("ji"))
1984             lang = wxT("yi");
1985         else if (langOrig == wxT("no_NO"))
1986             lang = wxT("nb_NO");
1987         else if (langOrig == wxT("no_NY"))
1988             lang = wxT("nn_NO");
1989         else if (langOrig == wxT("no"))
1990             lang = wxT("nb_NO");
1991         else
1992             lang = langOrig;
1993 
1994         // did we change it?
1995         if ( lang != langOrig )
1996         {
1997             langFull = lang + ExtractNotLang(langFull);
1998         }
1999 
2000         // 1. Try to find the language either as is:
2001         // a) With modifier if set
2002         if ( !modifier.empty() )
2003         {
2004             wxString langFullWithModifier = langFull + modifier;
2005             for ( i = 0; i < count; i++ )
2006             {
2007                 if ( ms_languagesDB->Item(i).CanonicalName == langFullWithModifier )
2008                     break;
2009             }
2010         }
2011 
2012         // b) Without modifier
2013         if ( modifier.empty() || i == count )
2014         {
2015             for ( i = 0; i < count; i++ )
2016             {
2017                 if ( ms_languagesDB->Item(i).CanonicalName == langFull )
2018                     break;
2019             }
2020         }
2021 
2022         // 2. If langFull is of the form xx_YY, try to find xx:
2023         if ( i == count && !justLang )
2024         {
2025             for ( i = 0; i < count; i++ )
2026             {
2027                 if ( ms_languagesDB->Item(i).CanonicalName == lang )
2028                 {
2029                     break;
2030                 }
2031             }
2032         }
2033 
2034         // 3. If langFull is of the form xx, try to find any xx_YY record:
2035         if ( i == count && justLang )
2036         {
2037             for ( i = 0; i < count; i++ )
2038             {
2039                 if ( ExtractLang(ms_languagesDB->Item(i).CanonicalName)
2040                         == langFull )
2041                 {
2042                     break;
2043                 }
2044             }
2045         }
2046     }
2047     else // not standard format
2048     {
2049         // try to find the name in verbose description
2050         for ( i = 0; i < count; i++ )
2051         {
2052             if (ms_languagesDB->Item(i).Description.CmpNoCase(langFull) == 0)
2053             {
2054                 break;
2055             }
2056         }
2057     }
2058 #elif defined(__WXMAC__)
2059     const wxChar * lc = NULL ;
2060     long lang = GetScriptVariable( smSystemScript, smScriptLang) ;
2061     switch( GetScriptManagerVariable( smRegionCode ) ) {
2062       case verUS :
2063         lc = wxT("en_US") ;
2064         break ;
2065       case verFrance :
2066         lc = wxT("fr_FR") ;
2067         break ;
2068       case verBritain :
2069         lc = wxT("en_GB") ;
2070         break ;
2071       case verGermany :
2072         lc = wxT("de_DE") ;
2073         break ;
2074       case verItaly :
2075         lc = wxT("it_IT") ;
2076         break ;
2077       case verNetherlands :
2078         lc = wxT("nl_NL") ;
2079         break ;
2080       case verFlemish :
2081         lc = wxT("nl_BE") ;
2082         break ;
2083       case verSweden :
2084         lc = wxT("sv_SE" );
2085         break ;
2086       case verSpain :
2087         lc = wxT("es_ES" );
2088         break ;
2089       case verDenmark :
2090         lc = wxT("da_DK") ;
2091         break ;
2092       case verPortugal :
2093         lc = wxT("pt_PT") ;
2094         break ;
2095       case verFrCanada:
2096         lc = wxT("fr_CA") ;
2097         break ;
2098       case verNorway:
2099         lc = wxT("nb_NO") ;
2100         break ;
2101       case verIsrael:
2102         lc = wxT("iw_IL") ;
2103         break ;
2104       case verJapan:
2105         lc = wxT("ja_JP") ;
2106         break ;
2107       case verAustralia:
2108         lc = wxT("en_AU") ;
2109         break ;
2110       case verArabic:
2111         lc = wxT("ar") ;
2112         break ;
2113       case verFinland:
2114         lc = wxT("fi_FI") ;
2115         break ;
2116       case verFrSwiss:
2117         lc = wxT("fr_CH") ;
2118         break ;
2119       case verGrSwiss:
2120         lc = wxT("de_CH") ;
2121         break ;
2122       case verGreece:
2123         lc = wxT("el_GR") ;
2124         break ;
2125       case verIceland:
2126         lc = wxT("is_IS") ;
2127         break ;
2128       case verMalta:
2129         lc = wxT("mt_MT") ;
2130         break ;
2131       case verCyprus:
2132       // _CY is not part of wx, so we have to translate according to the system language
2133         if ( lang == langGreek ) {
2134           lc = wxT("el_GR") ;
2135         }
2136         else if ( lang == langTurkish ) {
2137           lc = wxT("tr_TR") ;
2138         }
2139         break ;
2140       case verTurkey:
2141         lc = wxT("tr_TR") ;
2142         break ;
2143       case verYugoCroatian:
2144         lc = wxT("hr_HR") ;
2145         break ;
2146       case verIndiaHindi:
2147         lc = wxT("hi_IN") ;
2148         break ;
2149       case verPakistanUrdu:
2150         lc = wxT("ur_PK") ;
2151         break ;
2152       case verTurkishModified:
2153         lc = wxT("tr_TR") ;
2154         break ;
2155       case verItalianSwiss:
2156         lc = wxT("it_CH") ;
2157         break ;
2158       case verInternational:
2159         lc = wxT("en") ;
2160         break ;
2161       case verRomania:
2162         lc = wxT("ro_RO") ;
2163         break ;
2164       case verGreecePoly:
2165         lc = wxT("el_GR") ;
2166         break ;
2167       case verLithuania:
2168         lc = wxT("lt_LT") ;
2169         break ;
2170       case verPoland:
2171         lc = wxT("pl_PL") ;
2172         break ;
2173       case verMagyar :
2174       case verHungary:
2175         lc = wxT("hu_HU") ;
2176         break ;
2177       case verEstonia:
2178         lc = wxT("et_EE") ;
2179         break ;
2180       case verLatvia:
2181         lc = wxT("lv_LV") ;
2182         break ;
2183       case verSami:
2184         lc = wxT("se_NO") ;
2185         break ;
2186       case verFaroeIsl:
2187         lc = wxT("fo_FO") ;
2188         break ;
2189       case verIran:
2190         lc = wxT("fa_IR") ;
2191         break ;
2192       case verRussia:
2193         lc = wxT("ru_RU") ;
2194         break ;
2195        case verIreland:
2196         lc = wxT("ga_IE") ;
2197         break ;
2198       case verKorea:
2199         lc = wxT("ko_KR") ;
2200         break ;
2201       case verChina:
2202         lc = wxT("zh_CN") ;
2203         break ;
2204       case verTaiwan:
2205         lc = wxT("zh_TW") ;
2206         break ;
2207       case verThailand:
2208         lc = wxT("th_TH") ;
2209         break ;
2210       case verCzech:
2211         lc = wxT("cs_CZ") ;
2212         break ;
2213       case verSlovak:
2214         lc = wxT("sk_SK") ;
2215         break ;
2216       case verBengali:
2217         lc = wxT("bn") ;
2218         break ;
2219       case verByeloRussian:
2220         lc = wxT("be_BY") ;
2221         break ;
2222       case verUkraine:
2223         lc = wxT("uk_UA") ;
2224         break ;
2225       case verGreeceAlt:
2226         lc = wxT("el_GR") ;
2227         break ;
2228       case verSerbian:
2229         lc = wxT("sr_YU") ;
2230         break ;
2231       case verSlovenian:
2232         lc = wxT("sl_SI") ;
2233         break ;
2234       case verMacedonian:
2235         lc = wxT("mk_MK") ;
2236         break ;
2237       case verCroatia:
2238         lc = wxT("hr_HR") ;
2239         break ;
2240       case verBrazil:
2241         lc = wxT("pt_BR ") ;
2242         break ;
2243       case verBulgaria:
2244         lc = wxT("bg_BG") ;
2245         break ;
2246       case verCatalonia:
2247         lc = wxT("ca_ES") ;
2248         break ;
2249       case verScottishGaelic:
2250         lc = wxT("gd") ;
2251         break ;
2252       case verManxGaelic:
2253         lc = wxT("gv") ;
2254         break ;
2255       case verBreton:
2256         lc = wxT("br") ;
2257         break ;
2258       case verNunavut:
2259         lc = wxT("iu_CA") ;
2260         break ;
2261       case verWelsh:
2262         lc = wxT("cy") ;
2263         break ;
2264       case verIrishGaelicScript:
2265         lc = wxT("ga_IE") ;
2266         break ;
2267       case verEngCanada:
2268         lc = wxT("en_CA") ;
2269         break ;
2270       case verBhutan:
2271         lc = wxT("dz_BT") ;
2272         break ;
2273       case verArmenian:
2274         lc = wxT("hy_AM") ;
2275         break ;
2276       case verGeorgian:
2277         lc = wxT("ka_GE") ;
2278         break ;
2279       case verSpLatinAmerica:
2280         lc = wxT("es_AR") ;
2281         break ;
2282       case verTonga:
2283         lc = wxT("to_TO" );
2284         break ;
2285       case verFrenchUniversal:
2286         lc = wxT("fr_FR") ;
2287         break ;
2288       case verAustria:
2289         lc = wxT("de_AT") ;
2290         break ;
2291       case verGujarati:
2292         lc = wxT("gu_IN") ;
2293         break ;
2294       case verPunjabi:
2295         lc = wxT("pa") ;
2296         break ;
2297       case verIndiaUrdu:
2298         lc = wxT("ur_IN") ;
2299         break ;
2300       case verVietnam:
2301         lc = wxT("vi_VN") ;
2302         break ;
2303       case verFrBelgium:
2304         lc = wxT("fr_BE") ;
2305         break ;
2306       case verUzbek:
2307         lc = wxT("uz_UZ") ;
2308         break ;
2309       case verSingapore:
2310         lc = wxT("zh_SG") ;
2311         break ;
2312       case verNynorsk:
2313         lc = wxT("nn_NO") ;
2314         break ;
2315       case verAfrikaans:
2316         lc = wxT("af_ZA") ;
2317         break ;
2318       case verEsperanto:
2319         lc = wxT("eo") ;
2320         break ;
2321       case verMarathi:
2322         lc = wxT("mr_IN") ;
2323         break ;
2324       case verTibetan:
2325         lc = wxT("bo") ;
2326         break ;
2327       case verNepal:
2328         lc = wxT("ne_NP") ;
2329         break ;
2330       case verGreenland:
2331         lc = wxT("kl_GL") ;
2332         break ;
2333       default :
2334         break ;
2335     }
2336     if ( !lc )
2337         return wxLANGUAGE_UNKNOWN;
2338     for ( i = 0; i < count; i++ )
2339     {
2340         if ( ms_languagesDB->Item(i).CanonicalName == lc )
2341         {
2342             break;
2343         }
2344     }
2345 
2346 #elif defined(__WIN32__)
2347     LCID lcid = GetUserDefaultLCID();
2348     if ( lcid != 0 )
2349     {
2350         wxUint32 lang = PRIMARYLANGID(LANGIDFROMLCID(lcid));
2351         wxUint32 sublang = SUBLANGID(LANGIDFROMLCID(lcid));
2352 
2353         for ( i = 0; i < count; i++ )
2354         {
2355             if (ms_languagesDB->Item(i).WinLang == lang &&
2356                 ms_languagesDB->Item(i).WinSublang == sublang)
2357             {
2358                 break;
2359             }
2360         }
2361     }
2362     //else: leave wxlang == wxLANGUAGE_UNKNOWN
2363 #endif // Unix/Win32
2364 
2365     if ( i < count )
2366     {
2367         // we did find a matching entry, use it
2368         return ms_languagesDB->Item(i).Language;
2369     }
2370 
2371     // no info about this language in the database
2372     return wxLANGUAGE_UNKNOWN;
2373 }
2374 
2375 // ----------------------------------------------------------------------------
2376 // encoding stuff
2377 // ----------------------------------------------------------------------------
2378 
2379 // this is a bit strange as under Windows we get the encoding name using its
2380 // numeric value and under Unix we do it the other way round, but this just
2381 // reflects the way different systems provide the encoding info
2382 
2383 /* static */
GetSystemEncodingName()2384 wxString wxLocale::GetSystemEncodingName()
2385 {
2386     wxString encname;
2387 
2388 #if defined(__WIN32__) && !defined(__WXMICROWIN__)
2389     // FIXME: what is the error return value for GetACP()?
2390     UINT codepage = ::GetACP();
2391     encname.Printf(_T("windows-%u"), codepage);
2392 #elif defined(__WXMAC__)
2393     // default is just empty string, this resolves to the default system
2394     // encoding later
2395 #elif defined(__UNIX_LIKE__)
2396 
2397 #if defined(HAVE_LANGINFO_H) && defined(CODESET)
2398     // GNU libc provides current character set this way (this conforms
2399     // to Unix98)
2400     char *oldLocale = strdup(setlocale(LC_CTYPE, NULL));
2401     setlocale(LC_CTYPE, "");
2402     const char *alang = nl_langinfo(CODESET);
2403     setlocale(LC_CTYPE, oldLocale);
2404     free(oldLocale);
2405 
2406     if ( alang )
2407     {
2408         encname = wxString::FromAscii( alang );
2409     }
2410     else // nl_langinfo() failed
2411 #endif // HAVE_LANGINFO_H
2412     {
2413         // if we can't get at the character set directly, try to see if it's in
2414         // the environment variables (in most cases this won't work, but I was
2415         // out of ideas)
2416         char *lang = getenv( "LC_ALL");
2417         char *dot = lang ? strchr(lang, '.') : (char *)NULL;
2418         if (!dot)
2419         {
2420             lang = getenv( "LC_CTYPE" );
2421             if ( lang )
2422                 dot = strchr(lang, '.' );
2423         }
2424         if (!dot)
2425         {
2426             lang = getenv( "LANG");
2427             if ( lang )
2428                 dot = strchr(lang, '.');
2429         }
2430 
2431         if ( dot )
2432         {
2433             encname = wxString::FromAscii( dot+1 );
2434         }
2435     }
2436 #endif // Win32/Unix
2437 
2438     return encname;
2439 }
2440 
2441 /* static */
GetSystemEncoding()2442 wxFontEncoding wxLocale::GetSystemEncoding()
2443 {
2444 #if defined(__WIN32__) && !defined(__WXMICROWIN__)
2445     UINT codepage = ::GetACP();
2446 
2447     // wxWidgets only knows about CP1250-1257, 874, 932, 936, 949, 950
2448     if ( codepage >= 1250 && codepage <= 1257 )
2449     {
2450         return (wxFontEncoding)(wxFONTENCODING_CP1250 + codepage - 1250);
2451     }
2452 
2453     if ( codepage == 874 )
2454     {
2455         return wxFONTENCODING_CP874;
2456     }
2457 
2458     if ( codepage == 932 )
2459     {
2460         return wxFONTENCODING_CP932;
2461     }
2462 
2463     if ( codepage == 936 )
2464     {
2465         return wxFONTENCODING_CP936;
2466     }
2467 
2468     if ( codepage == 949 )
2469     {
2470         return wxFONTENCODING_CP949;
2471     }
2472 
2473     if ( codepage == 950 )
2474     {
2475         return wxFONTENCODING_CP950;
2476     }
2477 #elif defined(__WXMAC__)
2478     TextEncoding encoding = 0 ;
2479 #if TARGET_CARBON
2480     encoding = CFStringGetSystemEncoding() ;
2481 #else
2482     UpgradeScriptInfoToTextEncoding ( smSystemScript , kTextLanguageDontCare , kTextRegionDontCare , NULL , &encoding ) ;
2483 #endif
2484     return wxMacGetFontEncFromSystemEnc( encoding ) ;
2485 #elif defined(__UNIX_LIKE__) && wxUSE_FONTMAP
2486     const wxString encname = GetSystemEncodingName();
2487     if ( !encname.empty() )
2488     {
2489         wxFontEncoding enc = wxFontMapperBase::GetEncodingFromName(encname);
2490 
2491         // on some modern Linux systems (RedHat 8) the default system locale
2492         // is UTF8 -- but it isn't supported by wxGTK1 in ANSI build at all so
2493         // don't even try to use it in this case
2494 #if !wxUSE_UNICODE && \
2495         ((defined(__WXGTK__) && !defined(__WXGTK20__)) || defined(__WXMOTIF__))
2496         if ( enc == wxFONTENCODING_UTF8 )
2497         {
2498             // the most similar supported encoding...
2499             enc = wxFONTENCODING_ISO8859_1;
2500         }
2501 #endif // !wxUSE_UNICODE
2502 
2503         // GetEncodingFromName() returns wxFONTENCODING_DEFAULT for C locale
2504         // (a.k.a. US-ASCII) which is arguably a bug but keep it like this for
2505         // backwards compatibility and just take care to not return
2506         // wxFONTENCODING_DEFAULT from here as this surely doesn't make sense
2507         if ( enc == wxFONTENCODING_DEFAULT )
2508         {
2509             // we don't have wxFONTENCODING_ASCII, so use the closest one
2510             return wxFONTENCODING_ISO8859_1;
2511         }
2512 
2513         if ( enc != wxFONTENCODING_MAX )
2514         {
2515             return enc;
2516         }
2517         //else: return wxFONTENCODING_SYSTEM below
2518     }
2519 #endif // Win32/Unix
2520 
2521     return wxFONTENCODING_SYSTEM;
2522 }
2523 
2524 /* static */
AddLanguage(const wxLanguageInfo & info)2525 void wxLocale::AddLanguage(const wxLanguageInfo& info)
2526 {
2527     CreateLanguagesDB();
2528     ms_languagesDB->Add(info);
2529 }
2530 
2531 /* static */
GetLanguageInfo(int lang)2532 const wxLanguageInfo *wxLocale::GetLanguageInfo(int lang)
2533 {
2534     CreateLanguagesDB();
2535 
2536     // calling GetLanguageInfo(wxLANGUAGE_DEFAULT) is a natural thing to do, so
2537     // make it work
2538     if ( lang == wxLANGUAGE_DEFAULT )
2539         lang = GetSystemLanguage();
2540 
2541     const size_t count = ms_languagesDB->GetCount();
2542     for ( size_t i = 0; i < count; i++ )
2543     {
2544         if ( ms_languagesDB->Item(i).Language == lang )
2545         {
2546             // We need to create a temporary here in order to make this work with BCC in final build mode
2547             wxLanguageInfo *ptr = &ms_languagesDB->Item(i);
2548             return ptr;
2549         }
2550     }
2551 
2552     return NULL;
2553 }
2554 
2555 /* static */
GetLanguageName(int lang)2556 wxString wxLocale::GetLanguageName(int lang)
2557 {
2558     const wxLanguageInfo *info = GetLanguageInfo(lang);
2559     if ( !info )
2560         return wxEmptyString;
2561     else
2562         return info->Description;
2563 }
2564 
2565 /* static */
FindLanguageInfo(const wxString & locale)2566 const wxLanguageInfo *wxLocale::FindLanguageInfo(const wxString& locale)
2567 {
2568     CreateLanguagesDB();
2569 
2570     const wxLanguageInfo *infoRet = NULL;
2571 
2572     const size_t count = ms_languagesDB->GetCount();
2573     for ( size_t i = 0; i < count; i++ )
2574     {
2575         const wxLanguageInfo *info = &ms_languagesDB->Item(i);
2576 
2577         if ( wxStricmp(locale, info->CanonicalName) == 0 ||
2578                 wxStricmp(locale, info->Description) == 0 )
2579         {
2580             // exact match, stop searching
2581             infoRet = info;
2582             break;
2583         }
2584 
2585         if ( wxStricmp(locale, info->CanonicalName.BeforeFirst(_T('_'))) == 0 )
2586         {
2587             // a match -- but maybe we'll find an exact one later, so continue
2588             // looking
2589             //
2590             // OTOH, maybe we had already found a language match and in this
2591             // case don't overwrite it becauce the entry for the default
2592             // country always appears first in ms_languagesDB
2593             if ( !infoRet )
2594                 infoRet = info;
2595         }
2596     }
2597 
2598     return infoRet;
2599 }
2600 
GetSysName() const2601 wxString wxLocale::GetSysName() const
2602 {
2603             // FIXME
2604 #ifndef __WXWINCE__
2605     return wxSetlocale(LC_ALL, NULL);
2606 #else
2607     return wxEmptyString;
2608 #endif
2609 }
2610 
2611 // clean up
~wxLocale()2612 wxLocale::~wxLocale()
2613 {
2614     // free memory
2615     wxMsgCatalog *pTmpCat;
2616     while ( m_pMsgCat != NULL ) {
2617         pTmpCat = m_pMsgCat;
2618         m_pMsgCat = m_pMsgCat->m_pNext;
2619         delete pTmpCat;
2620     }
2621 
2622     // restore old locale pointer
2623     wxSetLocale(m_pOldLocale);
2624 
2625     // FIXME
2626 #ifndef __WXWINCE__
2627     wxSetlocale(LC_ALL, m_pszOldLocale);
2628 #endif
2629     free((wxChar *)m_pszOldLocale);     // const_cast
2630 }
2631 
2632 // get the translation of given string in current locale
GetString(const wxChar * szOrigString,const wxChar * szDomain) const2633 const wxChar *wxLocale::GetString(const wxChar *szOrigString,
2634                                   const wxChar *szDomain) const
2635 {
2636     return GetString(szOrigString, szOrigString, size_t(-1), szDomain);
2637 }
2638 
GetString(const wxChar * szOrigString,const wxChar * szOrigString2,size_t n,const wxChar * szDomain) const2639 const wxChar *wxLocale::GetString(const wxChar *szOrigString,
2640                                   const wxChar *szOrigString2,
2641                                   size_t n,
2642                                   const wxChar *szDomain) const
2643 {
2644     if ( wxIsEmpty(szOrigString) )
2645         return wxEmptyString;
2646 
2647     const wxChar *pszTrans = NULL;
2648     wxMsgCatalog *pMsgCat;
2649 
2650     if ( szDomain != NULL && szDomain[0] )
2651     {
2652         pMsgCat = FindCatalog(szDomain);
2653 
2654         // does the catalog exist?
2655         if ( pMsgCat != NULL )
2656             pszTrans = pMsgCat->GetString(szOrigString, n);
2657     }
2658     else
2659     {
2660         // search in all domains
2661         for ( pMsgCat = m_pMsgCat; pMsgCat != NULL; pMsgCat = pMsgCat->m_pNext )
2662         {
2663             pszTrans = pMsgCat->GetString(szOrigString, n);
2664             if ( pszTrans != NULL )   // take the first found
2665                 break;
2666         }
2667     }
2668 
2669     if ( pszTrans == NULL )
2670     {
2671 #ifdef __WXDEBUG__
2672         if ( !NoTransErr::Suppress() )
2673         {
2674             NoTransErr noTransErr;
2675 
2676             wxLogTrace(TRACE_I18N,
2677                        _T("string \"%s\"[%ld] not found in %slocale '%s'."),
2678                        szOrigString, (long)n,
2679                        szDomain ? wxString::Format(_T("domain '%s' "), szDomain).c_str()
2680                                 : _T(""),
2681                        m_strLocale.c_str());
2682         }
2683 #endif // __WXDEBUG__
2684 
2685         if (n == size_t(-1))
2686             return szOrigString;
2687         else
2688             return n == 1 ? szOrigString : szOrigString2;
2689     }
2690 
2691     return pszTrans;
2692 }
2693 
GetHeaderValue(const wxChar * szHeader,const wxChar * szDomain) const2694 wxString wxLocale::GetHeaderValue( const wxChar* szHeader,
2695                                    const wxChar* szDomain ) const
2696 {
2697     if ( wxIsEmpty(szHeader) )
2698         return wxEmptyString;
2699 
2700     wxChar const * pszTrans = NULL;
2701     wxMsgCatalog *pMsgCat;
2702 
2703     if ( szDomain != NULL )
2704     {
2705         pMsgCat = FindCatalog(szDomain);
2706 
2707         // does the catalog exist?
2708         if ( pMsgCat == NULL )
2709             return wxEmptyString;
2710 
2711         pszTrans = pMsgCat->GetString(wxEmptyString, (size_t)-1);
2712     }
2713     else
2714     {
2715         // search in all domains
2716         for ( pMsgCat = m_pMsgCat; pMsgCat != NULL; pMsgCat = pMsgCat->m_pNext )
2717         {
2718             pszTrans = pMsgCat->GetString(wxEmptyString, (size_t)-1);
2719             if ( pszTrans != NULL )   // take the first found
2720                 break;
2721         }
2722     }
2723 
2724     if ( wxIsEmpty(pszTrans) )
2725       return wxEmptyString;
2726 
2727     wxChar const * pszFound = wxStrstr(pszTrans, szHeader);
2728     if ( pszFound == NULL )
2729       return wxEmptyString;
2730 
2731     pszFound += wxStrlen(szHeader) + 2 /* ': ' */;
2732 
2733     // Every header is separated by \n
2734 
2735     wxChar const * pszEndLine = wxStrchr(pszFound, wxT('\n'));
2736     if ( pszEndLine == NULL ) pszEndLine = pszFound + wxStrlen(pszFound);
2737 
2738 
2739     // wxString( wxChar*, length);
2740     wxString retVal( pszFound, pszEndLine - pszFound );
2741 
2742     return retVal;
2743 }
2744 
2745 
2746 // find catalog by name in a linked list, return NULL if !found
FindCatalog(const wxChar * szDomain) const2747 wxMsgCatalog *wxLocale::FindCatalog(const wxChar *szDomain) const
2748 {
2749     // linear search in the linked list
2750     wxMsgCatalog *pMsgCat;
2751     for ( pMsgCat = m_pMsgCat; pMsgCat != NULL; pMsgCat = pMsgCat->m_pNext )
2752     {
2753         if ( wxStricmp(pMsgCat->GetName(), szDomain) == 0 )
2754           return pMsgCat;
2755     }
2756 
2757     return NULL;
2758 }
2759 
2760 // check if the given locale is provided by OS and C run time
2761 /* static */
IsAvailable(int lang)2762 bool wxLocale::IsAvailable(int lang)
2763 {
2764     const wxLanguageInfo *info = wxLocale::GetLanguageInfo(lang);
2765     wxCHECK_MSG( info, false, _T("invalid language") );
2766 
2767 #if defined(__WIN32__)
2768     if ( !info->WinLang )
2769         return false;
2770 
2771     if ( !::IsValidLocale
2772             (
2773                 MAKELCID(MAKELANGID(info->WinLang, info->WinSublang),
2774                          SORT_DEFAULT),
2775                 LCID_INSTALLED
2776             ) )
2777         return false;
2778 
2779 #elif defined(__UNIX__)
2780 
2781     // Test if setting the locale works, then set it back.
2782     wxMB2WXbuf oldLocale = wxSetlocale(LC_ALL, wxEmptyString);
2783     wxMB2WXbuf tmp = wxSetlocaleTryUTF(LC_ALL, info->CanonicalName);
2784     if ( !tmp )
2785     {
2786         // Some C libraries don't like xx_YY form and require xx only
2787         tmp = wxSetlocaleTryUTF(LC_ALL, info->CanonicalName.Left(2));
2788         if ( !tmp )
2789             return false;
2790     }
2791     // restore the original locale
2792     wxSetlocale(LC_ALL, oldLocale);
2793 #endif
2794 
2795     return true;
2796 }
2797 
2798 // check if the given catalog is loaded
IsLoaded(const wxChar * szDomain) const2799 bool wxLocale::IsLoaded(const wxChar *szDomain) const
2800 {
2801   return FindCatalog(szDomain) != NULL;
2802 }
2803 
2804 // add a catalog to our linked list
AddCatalog(const wxChar * szDomain)2805 bool wxLocale::AddCatalog(const wxChar *szDomain)
2806 {
2807     return AddCatalog(szDomain, wxLANGUAGE_ENGLISH_US, NULL);
2808 }
2809 
2810 // add a catalog to our linked list
AddCatalog(const wxChar * szDomain,wxLanguage msgIdLanguage,const wxChar * msgIdCharset)2811 bool wxLocale::AddCatalog(const wxChar *szDomain,
2812                           wxLanguage    msgIdLanguage,
2813                           const wxChar *msgIdCharset)
2814 
2815 {
2816   wxMsgCatalog *pMsgCat = new wxMsgCatalog;
2817 
2818   if ( pMsgCat->Load(m_strShort, szDomain, msgIdCharset, m_bConvertEncoding) ) {
2819     // add it to the head of the list so that in GetString it will
2820     // be searched before the catalogs added earlier
2821     pMsgCat->m_pNext = m_pMsgCat;
2822     m_pMsgCat = pMsgCat;
2823 
2824     return true;
2825   }
2826   else {
2827     // don't add it because it couldn't be loaded anyway
2828     delete pMsgCat;
2829 
2830     // It is OK to not load catalog if the msgid language and m_language match,
2831     // in which case we can directly display the texts embedded in program's
2832     // source code:
2833     if (m_language == msgIdLanguage)
2834         return true;
2835 
2836     // If there's no exact match, we may still get partial match where the
2837     // (basic) language is same, but the country differs. For example, it's
2838     // permitted to use en_US strings from sources even if m_language is en_GB:
2839     const wxLanguageInfo *msgIdLangInfo = GetLanguageInfo(msgIdLanguage);
2840     if ( msgIdLangInfo &&
2841          msgIdLangInfo->CanonicalName.Mid(0, 2) == m_strShort.Mid(0, 2) )
2842     {
2843         return true;
2844     }
2845 
2846     return false;
2847   }
2848 }
2849 
2850 // ----------------------------------------------------------------------------
2851 // accessors for locale-dependent data
2852 // ----------------------------------------------------------------------------
2853 
2854 #ifdef __WXMSW__
2855 
2856 /* static */
GetInfo(wxLocaleInfo index,wxLocaleCategory WXUNUSED (cat))2857 wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory WXUNUSED(cat))
2858 {
2859     wxUint32 lcid = LOCALE_USER_DEFAULT;
2860 
2861     if (wxGetLocale())
2862     {
2863         const wxLanguageInfo *info = GetLanguageInfo(wxGetLocale()->GetLanguage());
2864         if (info)
2865         {                         ;
2866             lcid = MAKELCID(MAKELANGID(info->WinLang, info->WinSublang),
2867                                      SORT_DEFAULT);
2868         }
2869     }
2870 
2871     wxString str;
2872     wxChar buffer[256];
2873     size_t count;
2874     buffer[0] = wxT('\0');
2875     switch (index)
2876     {
2877         case wxLOCALE_DECIMAL_POINT:
2878             count = ::GetLocaleInfo(lcid, LOCALE_SDECIMAL, buffer, 256);
2879             if (!count)
2880                 str << wxT(".");
2881             else
2882                 str << buffer;
2883             break;
2884 #if 0
2885         case wxSYS_LIST_SEPARATOR:
2886             count = ::GetLocaleInfo(lcid, LOCALE_SLIST, buffer, 256);
2887             if (!count)
2888                 str << wxT(",");
2889             else
2890                 str << buffer;
2891             break;
2892         case wxSYS_LEADING_ZERO: // 0 means no leading zero, 1 means leading zero
2893             count = ::GetLocaleInfo(lcid, LOCALE_ILZERO, buffer, 256);
2894             if (!count)
2895                 str << wxT("0");
2896             else
2897                 str << buffer;
2898             break;
2899 #endif
2900         default:
2901             wxFAIL_MSG(wxT("Unknown System String !"));
2902     }
2903     return str;
2904 }
2905 
2906 #elif defined(__DARWIN__)
2907 
2908 /* static */
GetInfo(wxLocaleInfo index,wxLocaleCategory WXUNUSED (cat))2909 wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory WXUNUSED(cat))
2910 {
2911     CFLocaleRef userLocaleRefRaw;
2912     if ( wxGetLocale() )
2913     {
2914         userLocaleRefRaw = CFLocaleCreate
2915                            (
2916                                 kCFAllocatorDefault,
2917                                 wxMacCFStringHolder(wxGetLocale()->GetCanonicalName())
2918                            );
2919     }
2920     else // no current locale, use the default one
2921     {
2922         userLocaleRefRaw = CFLocaleCopyCurrent();
2923     }
2924 
2925     wxCFRef<CFLocaleRef> userLocaleRef(userLocaleRefRaw);
2926 
2927     CFTypeRef cfstr;
2928     switch ( index )
2929     {
2930         case wxLOCALE_THOUSANDS_SEP:
2931             cfstr = CFLocaleGetValue(userLocaleRef, kCFLocaleGroupingSeparator);
2932             break;
2933 
2934         case wxLOCALE_DECIMAL_POINT:
2935             cfstr = CFLocaleGetValue(userLocaleRef, kCFLocaleDecimalSeparator);
2936             break;
2937 
2938         default:
2939             wxFAIL_MSG( _T("Unknown locale info") );
2940     }
2941 
2942     wxMacCFStringHolder
2943         str(CFStringCreateCopy(NULL, static_cast<CFStringRef>(cfstr)));
2944     return str.AsString();
2945 }
2946 
2947 #else // !__WXMSW__ && !__DARWIN__
2948 
2949 /* static */
GetInfo(wxLocaleInfo index,wxLocaleCategory cat)2950 wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory cat)
2951 {
2952     struct lconv *locale_info = localeconv();
2953     switch (cat)
2954     {
2955         case wxLOCALE_CAT_NUMBER:
2956             switch (index)
2957             {
2958                 case wxLOCALE_THOUSANDS_SEP:
2959                     return wxString(locale_info->thousands_sep,
2960                                     *wxConvCurrent);
2961                 case wxLOCALE_DECIMAL_POINT:
2962                     return wxString(locale_info->decimal_point,
2963                                     *wxConvCurrent);
2964                 default:
2965                     return wxEmptyString;
2966             }
2967         case wxLOCALE_CAT_MONEY:
2968             switch (index)
2969             {
2970                 case wxLOCALE_THOUSANDS_SEP:
2971                     return wxString(locale_info->mon_thousands_sep,
2972                                     *wxConvCurrent);
2973                 case wxLOCALE_DECIMAL_POINT:
2974                     return wxString(locale_info->mon_decimal_point,
2975                                     *wxConvCurrent);
2976                 default:
2977                     return wxEmptyString;
2978             }
2979         default:
2980             return wxEmptyString;
2981     }
2982 }
2983 
2984 #endif // __WXMSW__/!__WXMSW__
2985 
2986 // ----------------------------------------------------------------------------
2987 // global functions and variables
2988 // ----------------------------------------------------------------------------
2989 
2990 // retrieve/change current locale
2991 // ------------------------------
2992 
2993 // the current locale object
2994 static wxLocale *g_pLocale = NULL;
2995 
wxGetLocale()2996 wxLocale *wxGetLocale()
2997 {
2998   return g_pLocale;
2999 }
3000 
wxSetLocale(wxLocale * pLocale)3001 wxLocale *wxSetLocale(wxLocale *pLocale)
3002 {
3003   wxLocale *pOld = g_pLocale;
3004   g_pLocale = pLocale;
3005   return pOld;
3006 }
3007 
3008 
3009 
3010 // ----------------------------------------------------------------------------
3011 // wxLocale module (for lazy destruction of languagesDB)
3012 // ----------------------------------------------------------------------------
3013 
3014 class wxLocaleModule: public wxModule
3015 {
3016     DECLARE_DYNAMIC_CLASS(wxLocaleModule)
3017     public:
wxLocaleModule()3018         wxLocaleModule() {}
OnInit()3019         bool OnInit() { return true; }
OnExit()3020         void OnExit() { wxLocale::DestroyLanguagesDB(); }
3021 };
3022 
IMPLEMENT_DYNAMIC_CLASS(wxLocaleModule,wxModule)3023 IMPLEMENT_DYNAMIC_CLASS(wxLocaleModule, wxModule)
3024 
3025 
3026 
3027 // ----------------------------------------------------------------------------
3028 // default languages table & initialization
3029 // ----------------------------------------------------------------------------
3030 
3031 
3032 
3033 // --- --- --- generated code begins here --- --- ---
3034 
3035 // This table is generated by misc/languages/genlang.py
3036 // When making changes, please put them into misc/languages/langtabl.txt
3037 
3038 #if !defined(__WIN32__) || defined(__WXMICROWIN__)
3039 
3040 #define SETWINLANG(info,lang,sublang)
3041 
3042 #else
3043 
3044 #define SETWINLANG(info,lang,sublang) \
3045     info.WinLang = lang, info.WinSublang = sublang;
3046 
3047 #ifndef LANG_AFRIKAANS
3048 #define LANG_AFRIKAANS (0)
3049 #endif
3050 #ifndef LANG_ALBANIAN
3051 #define LANG_ALBANIAN (0)
3052 #endif
3053 #ifndef LANG_ARABIC
3054 #define LANG_ARABIC (0)
3055 #endif
3056 #ifndef LANG_ARMENIAN
3057 #define LANG_ARMENIAN (0)
3058 #endif
3059 #ifndef LANG_ASSAMESE
3060 #define LANG_ASSAMESE (0)
3061 #endif
3062 #ifndef LANG_AZERI
3063 #define LANG_AZERI (0)
3064 #endif
3065 #ifndef LANG_BASQUE
3066 #define LANG_BASQUE (0)
3067 #endif
3068 #ifndef LANG_BELARUSIAN
3069 #define LANG_BELARUSIAN (0)
3070 #endif
3071 #ifndef LANG_BENGALI
3072 #define LANG_BENGALI (0)
3073 #endif
3074 #ifndef LANG_BULGARIAN
3075 #define LANG_BULGARIAN (0)
3076 #endif
3077 #ifndef LANG_CATALAN
3078 #define LANG_CATALAN (0)
3079 #endif
3080 #ifndef LANG_CHINESE
3081 #define LANG_CHINESE (0)
3082 #endif
3083 #ifndef LANG_CROATIAN
3084 #define LANG_CROATIAN (0)
3085 #endif
3086 #ifndef LANG_CZECH
3087 #define LANG_CZECH (0)
3088 #endif
3089 #ifndef LANG_DANISH
3090 #define LANG_DANISH (0)
3091 #endif
3092 #ifndef LANG_DUTCH
3093 #define LANG_DUTCH (0)
3094 #endif
3095 #ifndef LANG_ENGLISH
3096 #define LANG_ENGLISH (0)
3097 #endif
3098 #ifndef LANG_ESTONIAN
3099 #define LANG_ESTONIAN (0)
3100 #endif
3101 #ifndef LANG_FAEROESE
3102 #define LANG_FAEROESE (0)
3103 #endif
3104 #ifndef LANG_FARSI
3105 #define LANG_FARSI (0)
3106 #endif
3107 #ifndef LANG_FINNISH
3108 #define LANG_FINNISH (0)
3109 #endif
3110 #ifndef LANG_FRENCH
3111 #define LANG_FRENCH (0)
3112 #endif
3113 #ifndef LANG_GEORGIAN
3114 #define LANG_GEORGIAN (0)
3115 #endif
3116 #ifndef LANG_GERMAN
3117 #define LANG_GERMAN (0)
3118 #endif
3119 #ifndef LANG_GREEK
3120 #define LANG_GREEK (0)
3121 #endif
3122 #ifndef LANG_GUJARATI
3123 #define LANG_GUJARATI (0)
3124 #endif
3125 #ifndef LANG_HEBREW
3126 #define LANG_HEBREW (0)
3127 #endif
3128 #ifndef LANG_HINDI
3129 #define LANG_HINDI (0)
3130 #endif
3131 #ifndef LANG_HUNGARIAN
3132 #define LANG_HUNGARIAN (0)
3133 #endif
3134 #ifndef LANG_ICELANDIC
3135 #define LANG_ICELANDIC (0)
3136 #endif
3137 #ifndef LANG_INDONESIAN
3138 #define LANG_INDONESIAN (0)
3139 #endif
3140 #ifndef LANG_ITALIAN
3141 #define LANG_ITALIAN (0)
3142 #endif
3143 #ifndef LANG_JAPANESE
3144 #define LANG_JAPANESE (0)
3145 #endif
3146 #ifndef LANG_KANNADA
3147 #define LANG_KANNADA (0)
3148 #endif
3149 #ifndef LANG_KASHMIRI
3150 #define LANG_KASHMIRI (0)
3151 #endif
3152 #ifndef LANG_KAZAK
3153 #define LANG_KAZAK (0)
3154 #endif
3155 #ifndef LANG_KONKANI
3156 #define LANG_KONKANI (0)
3157 #endif
3158 #ifndef LANG_KOREAN
3159 #define LANG_KOREAN (0)
3160 #endif
3161 #ifndef LANG_LATVIAN
3162 #define LANG_LATVIAN (0)
3163 #endif
3164 #ifndef LANG_LITHUANIAN
3165 #define LANG_LITHUANIAN (0)
3166 #endif
3167 #ifndef LANG_MACEDONIAN
3168 #define LANG_MACEDONIAN (0)
3169 #endif
3170 #ifndef LANG_MALAY
3171 #define LANG_MALAY (0)
3172 #endif
3173 #ifndef LANG_MALAYALAM
3174 #define LANG_MALAYALAM (0)
3175 #endif
3176 #ifndef LANG_MANIPURI
3177 #define LANG_MANIPURI (0)
3178 #endif
3179 #ifndef LANG_MARATHI
3180 #define LANG_MARATHI (0)
3181 #endif
3182 #ifndef LANG_NEPALI
3183 #define LANG_NEPALI (0)
3184 #endif
3185 #ifndef LANG_NORWEGIAN
3186 #define LANG_NORWEGIAN (0)
3187 #endif
3188 #ifndef LANG_ORIYA
3189 #define LANG_ORIYA (0)
3190 #endif
3191 #ifndef LANG_POLISH
3192 #define LANG_POLISH (0)
3193 #endif
3194 #ifndef LANG_PORTUGUESE
3195 #define LANG_PORTUGUESE (0)
3196 #endif
3197 #ifndef LANG_PUNJABI
3198 #define LANG_PUNJABI (0)
3199 #endif
3200 #ifndef LANG_ROMANIAN
3201 #define LANG_ROMANIAN (0)
3202 #endif
3203 #ifndef LANG_RUSSIAN
3204 #define LANG_RUSSIAN (0)
3205 #endif
3206 #ifndef LANG_SAMI
3207 #define LANG_SAMI (0)
3208 #endif
3209 #ifndef LANG_SANSKRIT
3210 #define LANG_SANSKRIT (0)
3211 #endif
3212 #ifndef LANG_SERBIAN
3213 #define LANG_SERBIAN (0)
3214 #endif
3215 #ifndef LANG_SINDHI
3216 #define LANG_SINDHI (0)
3217 #endif
3218 #ifndef LANG_SLOVAK
3219 #define LANG_SLOVAK (0)
3220 #endif
3221 #ifndef LANG_SLOVENIAN
3222 #define LANG_SLOVENIAN (0)
3223 #endif
3224 #ifndef LANG_SPANISH
3225 #define LANG_SPANISH (0)
3226 #endif
3227 #ifndef LANG_SWAHILI
3228 #define LANG_SWAHILI (0)
3229 #endif
3230 #ifndef LANG_SWEDISH
3231 #define LANG_SWEDISH (0)
3232 #endif
3233 #ifndef LANG_TAMIL
3234 #define LANG_TAMIL (0)
3235 #endif
3236 #ifndef LANG_TATAR
3237 #define LANG_TATAR (0)
3238 #endif
3239 #ifndef LANG_TELUGU
3240 #define LANG_TELUGU (0)
3241 #endif
3242 #ifndef LANG_THAI
3243 #define LANG_THAI (0)
3244 #endif
3245 #ifndef LANG_TURKISH
3246 #define LANG_TURKISH (0)
3247 #endif
3248 #ifndef LANG_UKRAINIAN
3249 #define LANG_UKRAINIAN (0)
3250 #endif
3251 #ifndef LANG_URDU
3252 #define LANG_URDU (0)
3253 #endif
3254 #ifndef LANG_UZBEK
3255 #define LANG_UZBEK (0)
3256 #endif
3257 #ifndef LANG_VALENCIAN
3258 #define LANG_VALENCIAN (0)
3259 #endif
3260 #ifndef LANG_VIETNAMESE
3261 #define LANG_VIETNAMESE (0)
3262 #endif
3263 #ifndef SUBLANG_ARABIC_ALGERIA
3264 #define SUBLANG_ARABIC_ALGERIA SUBLANG_DEFAULT
3265 #endif
3266 #ifndef SUBLANG_ARABIC_BAHRAIN
3267 #define SUBLANG_ARABIC_BAHRAIN SUBLANG_DEFAULT
3268 #endif
3269 #ifndef SUBLANG_ARABIC_EGYPT
3270 #define SUBLANG_ARABIC_EGYPT SUBLANG_DEFAULT
3271 #endif
3272 #ifndef SUBLANG_ARABIC_IRAQ
3273 #define SUBLANG_ARABIC_IRAQ SUBLANG_DEFAULT
3274 #endif
3275 #ifndef SUBLANG_ARABIC_JORDAN
3276 #define SUBLANG_ARABIC_JORDAN SUBLANG_DEFAULT
3277 #endif
3278 #ifndef SUBLANG_ARABIC_KUWAIT
3279 #define SUBLANG_ARABIC_KUWAIT SUBLANG_DEFAULT
3280 #endif
3281 #ifndef SUBLANG_ARABIC_LEBANON
3282 #define SUBLANG_ARABIC_LEBANON SUBLANG_DEFAULT
3283 #endif
3284 #ifndef SUBLANG_ARABIC_LIBYA
3285 #define SUBLANG_ARABIC_LIBYA SUBLANG_DEFAULT
3286 #endif
3287 #ifndef SUBLANG_ARABIC_MOROCCO
3288 #define SUBLANG_ARABIC_MOROCCO SUBLANG_DEFAULT
3289 #endif
3290 #ifndef SUBLANG_ARABIC_OMAN
3291 #define SUBLANG_ARABIC_OMAN SUBLANG_DEFAULT
3292 #endif
3293 #ifndef SUBLANG_ARABIC_QATAR
3294 #define SUBLANG_ARABIC_QATAR SUBLANG_DEFAULT
3295 #endif
3296 #ifndef SUBLANG_ARABIC_SAUDI_ARABIA
3297 #define SUBLANG_ARABIC_SAUDI_ARABIA SUBLANG_DEFAULT
3298 #endif
3299 #ifndef SUBLANG_ARABIC_SYRIA
3300 #define SUBLANG_ARABIC_SYRIA SUBLANG_DEFAULT
3301 #endif
3302 #ifndef SUBLANG_ARABIC_TUNISIA
3303 #define SUBLANG_ARABIC_TUNISIA SUBLANG_DEFAULT
3304 #endif
3305 #ifndef SUBLANG_ARABIC_UAE
3306 #define SUBLANG_ARABIC_UAE SUBLANG_DEFAULT
3307 #endif
3308 #ifndef SUBLANG_ARABIC_YEMEN
3309 #define SUBLANG_ARABIC_YEMEN SUBLANG_DEFAULT
3310 #endif
3311 #ifndef SUBLANG_AZERI_CYRILLIC
3312 #define SUBLANG_AZERI_CYRILLIC SUBLANG_DEFAULT
3313 #endif
3314 #ifndef SUBLANG_AZERI_LATIN
3315 #define SUBLANG_AZERI_LATIN SUBLANG_DEFAULT
3316 #endif
3317 #ifndef SUBLANG_CHINESE_SIMPLIFIED
3318 #define SUBLANG_CHINESE_SIMPLIFIED SUBLANG_DEFAULT
3319 #endif
3320 #ifndef SUBLANG_CHINESE_TRADITIONAL
3321 #define SUBLANG_CHINESE_TRADITIONAL SUBLANG_DEFAULT
3322 #endif
3323 #ifndef SUBLANG_CHINESE_HONGKONG
3324 #define SUBLANG_CHINESE_HONGKONG SUBLANG_DEFAULT
3325 #endif
3326 #ifndef SUBLANG_CHINESE_MACAU
3327 #define SUBLANG_CHINESE_MACAU SUBLANG_DEFAULT
3328 #endif
3329 #ifndef SUBLANG_CHINESE_SINGAPORE
3330 #define SUBLANG_CHINESE_SINGAPORE SUBLANG_DEFAULT
3331 #endif
3332 #ifndef SUBLANG_DUTCH
3333 #define SUBLANG_DUTCH SUBLANG_DEFAULT
3334 #endif
3335 #ifndef SUBLANG_DUTCH_BELGIAN
3336 #define SUBLANG_DUTCH_BELGIAN SUBLANG_DEFAULT
3337 #endif
3338 #ifndef SUBLANG_ENGLISH_UK
3339 #define SUBLANG_ENGLISH_UK SUBLANG_DEFAULT
3340 #endif
3341 #ifndef SUBLANG_ENGLISH_US
3342 #define SUBLANG_ENGLISH_US SUBLANG_DEFAULT
3343 #endif
3344 #ifndef SUBLANG_ENGLISH_AUS
3345 #define SUBLANG_ENGLISH_AUS SUBLANG_DEFAULT
3346 #endif
3347 #ifndef SUBLANG_ENGLISH_BELIZE
3348 #define SUBLANG_ENGLISH_BELIZE SUBLANG_DEFAULT
3349 #endif
3350 #ifndef SUBLANG_ENGLISH_CAN
3351 #define SUBLANG_ENGLISH_CAN SUBLANG_DEFAULT
3352 #endif
3353 #ifndef SUBLANG_ENGLISH_CARIBBEAN
3354 #define SUBLANG_ENGLISH_CARIBBEAN SUBLANG_DEFAULT
3355 #endif
3356 #ifndef SUBLANG_ENGLISH_EIRE
3357 #define SUBLANG_ENGLISH_EIRE SUBLANG_DEFAULT
3358 #endif
3359 #ifndef SUBLANG_ENGLISH_JAMAICA
3360 #define SUBLANG_ENGLISH_JAMAICA SUBLANG_DEFAULT
3361 #endif
3362 #ifndef SUBLANG_ENGLISH_NZ
3363 #define SUBLANG_ENGLISH_NZ SUBLANG_DEFAULT
3364 #endif
3365 #ifndef SUBLANG_ENGLISH_PHILIPPINES
3366 #define SUBLANG_ENGLISH_PHILIPPINES SUBLANG_DEFAULT
3367 #endif
3368 #ifndef SUBLANG_ENGLISH_SOUTH_AFRICA
3369 #define SUBLANG_ENGLISH_SOUTH_AFRICA SUBLANG_DEFAULT
3370 #endif
3371 #ifndef SUBLANG_ENGLISH_TRINIDAD
3372 #define SUBLANG_ENGLISH_TRINIDAD SUBLANG_DEFAULT
3373 #endif
3374 #ifndef SUBLANG_ENGLISH_ZIMBABWE
3375 #define SUBLANG_ENGLISH_ZIMBABWE SUBLANG_DEFAULT
3376 #endif
3377 #ifndef SUBLANG_FRENCH
3378 #define SUBLANG_FRENCH SUBLANG_DEFAULT
3379 #endif
3380 #ifndef SUBLANG_FRENCH_BELGIAN
3381 #define SUBLANG_FRENCH_BELGIAN SUBLANG_DEFAULT
3382 #endif
3383 #ifndef SUBLANG_FRENCH_CANADIAN
3384 #define SUBLANG_FRENCH_CANADIAN SUBLANG_DEFAULT
3385 #endif
3386 #ifndef SUBLANG_FRENCH_LUXEMBOURG
3387 #define SUBLANG_FRENCH_LUXEMBOURG SUBLANG_DEFAULT
3388 #endif
3389 #ifndef SUBLANG_FRENCH_MONACO
3390 #define SUBLANG_FRENCH_MONACO SUBLANG_DEFAULT
3391 #endif
3392 #ifndef SUBLANG_FRENCH_SWISS
3393 #define SUBLANG_FRENCH_SWISS SUBLANG_DEFAULT
3394 #endif
3395 #ifndef SUBLANG_GERMAN
3396 #define SUBLANG_GERMAN SUBLANG_DEFAULT
3397 #endif
3398 #ifndef SUBLANG_GERMAN_AUSTRIAN
3399 #define SUBLANG_GERMAN_AUSTRIAN SUBLANG_DEFAULT
3400 #endif
3401 #ifndef SUBLANG_GERMAN_LIECHTENSTEIN
3402 #define SUBLANG_GERMAN_LIECHTENSTEIN SUBLANG_DEFAULT
3403 #endif
3404 #ifndef SUBLANG_GERMAN_LUXEMBOURG
3405 #define SUBLANG_GERMAN_LUXEMBOURG SUBLANG_DEFAULT
3406 #endif
3407 #ifndef SUBLANG_GERMAN_SWISS
3408 #define SUBLANG_GERMAN_SWISS SUBLANG_DEFAULT
3409 #endif
3410 #ifndef SUBLANG_ITALIAN
3411 #define SUBLANG_ITALIAN SUBLANG_DEFAULT
3412 #endif
3413 #ifndef SUBLANG_ITALIAN_SWISS
3414 #define SUBLANG_ITALIAN_SWISS SUBLANG_DEFAULT
3415 #endif
3416 #ifndef SUBLANG_KASHMIRI_INDIA
3417 #define SUBLANG_KASHMIRI_INDIA SUBLANG_DEFAULT
3418 #endif
3419 #ifndef SUBLANG_KOREAN
3420 #define SUBLANG_KOREAN SUBLANG_DEFAULT
3421 #endif
3422 #ifndef SUBLANG_LITHUANIAN
3423 #define SUBLANG_LITHUANIAN SUBLANG_DEFAULT
3424 #endif
3425 #ifndef SUBLANG_MALAY_BRUNEI_DARUSSALAM
3426 #define SUBLANG_MALAY_BRUNEI_DARUSSALAM SUBLANG_DEFAULT
3427 #endif
3428 #ifndef SUBLANG_MALAY_MALAYSIA
3429 #define SUBLANG_MALAY_MALAYSIA SUBLANG_DEFAULT
3430 #endif
3431 #ifndef SUBLANG_NEPALI_INDIA
3432 #define SUBLANG_NEPALI_INDIA SUBLANG_DEFAULT
3433 #endif
3434 #ifndef SUBLANG_NORWEGIAN_BOKMAL
3435 #define SUBLANG_NORWEGIAN_BOKMAL SUBLANG_DEFAULT
3436 #endif
3437 #ifndef SUBLANG_NORWEGIAN_NYNORSK
3438 #define SUBLANG_NORWEGIAN_NYNORSK SUBLANG_DEFAULT
3439 #endif
3440 #ifndef SUBLANG_PORTUGUESE
3441 #define SUBLANG_PORTUGUESE SUBLANG_DEFAULT
3442 #endif
3443 #ifndef SUBLANG_PORTUGUESE_BRAZILIAN
3444 #define SUBLANG_PORTUGUESE_BRAZILIAN SUBLANG_DEFAULT
3445 #endif
3446 #ifndef SUBLANG_SERBIAN_CYRILLIC
3447 #define SUBLANG_SERBIAN_CYRILLIC SUBLANG_DEFAULT
3448 #endif
3449 #ifndef SUBLANG_SERBIAN_LATIN
3450 #define SUBLANG_SERBIAN_LATIN SUBLANG_DEFAULT
3451 #endif
3452 #ifndef SUBLANG_SPANISH
3453 #define SUBLANG_SPANISH SUBLANG_DEFAULT
3454 #endif
3455 #ifndef SUBLANG_SPANISH_ARGENTINA
3456 #define SUBLANG_SPANISH_ARGENTINA SUBLANG_DEFAULT
3457 #endif
3458 #ifndef SUBLANG_SPANISH_BOLIVIA
3459 #define SUBLANG_SPANISH_BOLIVIA SUBLANG_DEFAULT
3460 #endif
3461 #ifndef SUBLANG_SPANISH_CHILE
3462 #define SUBLANG_SPANISH_CHILE SUBLANG_DEFAULT
3463 #endif
3464 #ifndef SUBLANG_SPANISH_COLOMBIA
3465 #define SUBLANG_SPANISH_COLOMBIA SUBLANG_DEFAULT
3466 #endif
3467 #ifndef SUBLANG_SPANISH_COSTA_RICA
3468 #define SUBLANG_SPANISH_COSTA_RICA SUBLANG_DEFAULT
3469 #endif
3470 #ifndef SUBLANG_SPANISH_DOMINICAN_REPUBLIC
3471 #define SUBLANG_SPANISH_DOMINICAN_REPUBLIC SUBLANG_DEFAULT
3472 #endif
3473 #ifndef SUBLANG_SPANISH_ECUADOR
3474 #define SUBLANG_SPANISH_ECUADOR SUBLANG_DEFAULT
3475 #endif
3476 #ifndef SUBLANG_SPANISH_EL_SALVADOR
3477 #define SUBLANG_SPANISH_EL_SALVADOR SUBLANG_DEFAULT
3478 #endif
3479 #ifndef SUBLANG_SPANISH_GUATEMALA
3480 #define SUBLANG_SPANISH_GUATEMALA SUBLANG_DEFAULT
3481 #endif
3482 #ifndef SUBLANG_SPANISH_HONDURAS
3483 #define SUBLANG_SPANISH_HONDURAS SUBLANG_DEFAULT
3484 #endif
3485 #ifndef SUBLANG_SPANISH_MEXICAN
3486 #define SUBLANG_SPANISH_MEXICAN SUBLANG_DEFAULT
3487 #endif
3488 #ifndef SUBLANG_SPANISH_MODERN
3489 #define SUBLANG_SPANISH_MODERN SUBLANG_DEFAULT
3490 #endif
3491 #ifndef SUBLANG_SPANISH_NICARAGUA
3492 #define SUBLANG_SPANISH_NICARAGUA SUBLANG_DEFAULT
3493 #endif
3494 #ifndef SUBLANG_SPANISH_PANAMA
3495 #define SUBLANG_SPANISH_PANAMA SUBLANG_DEFAULT
3496 #endif
3497 #ifndef SUBLANG_SPANISH_PARAGUAY
3498 #define SUBLANG_SPANISH_PARAGUAY SUBLANG_DEFAULT
3499 #endif
3500 #ifndef SUBLANG_SPANISH_PERU
3501 #define SUBLANG_SPANISH_PERU SUBLANG_DEFAULT
3502 #endif
3503 #ifndef SUBLANG_SPANISH_PUERTO_RICO
3504 #define SUBLANG_SPANISH_PUERTO_RICO SUBLANG_DEFAULT
3505 #endif
3506 #ifndef SUBLANG_SPANISH_URUGUAY
3507 #define SUBLANG_SPANISH_URUGUAY SUBLANG_DEFAULT
3508 #endif
3509 #ifndef SUBLANG_SPANISH_VENEZUELA
3510 #define SUBLANG_SPANISH_VENEZUELA SUBLANG_DEFAULT
3511 #endif
3512 #ifndef SUBLANG_SWEDISH
3513 #define SUBLANG_SWEDISH SUBLANG_DEFAULT
3514 #endif
3515 #ifndef SUBLANG_SWEDISH_FINLAND
3516 #define SUBLANG_SWEDISH_FINLAND SUBLANG_DEFAULT
3517 #endif
3518 #ifndef SUBLANG_URDU_INDIA
3519 #define SUBLANG_URDU_INDIA SUBLANG_DEFAULT
3520 #endif
3521 #ifndef SUBLANG_URDU_PAKISTAN
3522 #define SUBLANG_URDU_PAKISTAN SUBLANG_DEFAULT
3523 #endif
3524 #ifndef SUBLANG_UZBEK_CYRILLIC
3525 #define SUBLANG_UZBEK_CYRILLIC SUBLANG_DEFAULT
3526 #endif
3527 #ifndef SUBLANG_UZBEK_LATIN
3528 #define SUBLANG_UZBEK_LATIN SUBLANG_DEFAULT
3529 #endif
3530 
3531 
3532 #endif // __WIN32__
3533 
3534 #define LNG(wxlang, canonical, winlang, winsublang, layout, desc) \
3535     info.Language = wxlang;                               \
3536     info.CanonicalName = wxT(canonical);                  \
3537     info.LayoutDirection = layout;                        \
3538     info.Description = wxT(desc);                         \
3539     SETWINLANG(info, winlang, winsublang)                 \
3540     AddLanguage(info);
3541 
3542 void wxLocale::InitLanguagesDB()
3543 {
3544    wxLanguageInfo info;
3545    wxStringTokenizer tkn;
3546 
3547    LNG(wxLANGUAGE_ABKHAZIAN,                  "ab"   , 0              , 0                                 , wxLayout_LeftToRight, "Abkhazian")
3548    LNG(wxLANGUAGE_AFAR,                       "aa"   , 0              , 0                                 , wxLayout_LeftToRight, "Afar")
3549    LNG(wxLANGUAGE_AFRIKAANS,                  "af_ZA", LANG_AFRIKAANS , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Afrikaans")
3550    LNG(wxLANGUAGE_ALBANIAN,                   "sq_AL", LANG_ALBANIAN  , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Albanian")
3551    LNG(wxLANGUAGE_AMHARIC,                    "am"   , 0              , 0                                 , wxLayout_LeftToRight, "Amharic")
3552    LNG(wxLANGUAGE_ARABIC,                     "ar"   , LANG_ARABIC    , SUBLANG_DEFAULT                   , wxLayout_RightToLeft, "Arabic")
3553    LNG(wxLANGUAGE_ARABIC_ALGERIA,             "ar_DZ", LANG_ARABIC    , SUBLANG_ARABIC_ALGERIA            , wxLayout_RightToLeft, "Arabic (Algeria)")
3554    LNG(wxLANGUAGE_ARABIC_BAHRAIN,             "ar_BH", LANG_ARABIC    , SUBLANG_ARABIC_BAHRAIN            , wxLayout_RightToLeft, "Arabic (Bahrain)")
3555    LNG(wxLANGUAGE_ARABIC_EGYPT,               "ar_EG", LANG_ARABIC    , SUBLANG_ARABIC_EGYPT              , wxLayout_RightToLeft, "Arabic (Egypt)")
3556    LNG(wxLANGUAGE_ARABIC_IRAQ,                "ar_IQ", LANG_ARABIC    , SUBLANG_ARABIC_IRAQ               , wxLayout_RightToLeft, "Arabic (Iraq)")
3557    LNG(wxLANGUAGE_ARABIC_JORDAN,              "ar_JO", LANG_ARABIC    , SUBLANG_ARABIC_JORDAN             , wxLayout_RightToLeft, "Arabic (Jordan)")
3558    LNG(wxLANGUAGE_ARABIC_KUWAIT,              "ar_KW", LANG_ARABIC    , SUBLANG_ARABIC_KUWAIT             , wxLayout_RightToLeft, "Arabic (Kuwait)")
3559    LNG(wxLANGUAGE_ARABIC_LEBANON,             "ar_LB", LANG_ARABIC    , SUBLANG_ARABIC_LEBANON            , wxLayout_RightToLeft, "Arabic (Lebanon)")
3560    LNG(wxLANGUAGE_ARABIC_LIBYA,               "ar_LY", LANG_ARABIC    , SUBLANG_ARABIC_LIBYA              , wxLayout_RightToLeft, "Arabic (Libya)")
3561    LNG(wxLANGUAGE_ARABIC_MOROCCO,             "ar_MA", LANG_ARABIC    , SUBLANG_ARABIC_MOROCCO            , wxLayout_RightToLeft, "Arabic (Morocco)")
3562    LNG(wxLANGUAGE_ARABIC_OMAN,                "ar_OM", LANG_ARABIC    , SUBLANG_ARABIC_OMAN               , wxLayout_RightToLeft, "Arabic (Oman)")
3563    LNG(wxLANGUAGE_ARABIC_QATAR,               "ar_QA", LANG_ARABIC    , SUBLANG_ARABIC_QATAR              , wxLayout_RightToLeft, "Arabic (Qatar)")
3564    LNG(wxLANGUAGE_ARABIC_SAUDI_ARABIA,        "ar_SA", LANG_ARABIC    , SUBLANG_ARABIC_SAUDI_ARABIA       , wxLayout_RightToLeft, "Arabic (Saudi Arabia)")
3565    LNG(wxLANGUAGE_ARABIC_SUDAN,               "ar_SD", 0              , 0                                 , wxLayout_RightToLeft, "Arabic (Sudan)")
3566    LNG(wxLANGUAGE_ARABIC_SYRIA,               "ar_SY", LANG_ARABIC    , SUBLANG_ARABIC_SYRIA              , wxLayout_RightToLeft, "Arabic (Syria)")
3567    LNG(wxLANGUAGE_ARABIC_TUNISIA,             "ar_TN", LANG_ARABIC    , SUBLANG_ARABIC_TUNISIA            , wxLayout_RightToLeft, "Arabic (Tunisia)")
3568    LNG(wxLANGUAGE_ARABIC_UAE,                 "ar_AE", LANG_ARABIC    , SUBLANG_ARABIC_UAE                , wxLayout_RightToLeft, "Arabic (Uae)")
3569    LNG(wxLANGUAGE_ARABIC_YEMEN,               "ar_YE", LANG_ARABIC    , SUBLANG_ARABIC_YEMEN              , wxLayout_RightToLeft, "Arabic (Yemen)")
3570    LNG(wxLANGUAGE_ARMENIAN,                   "hy"   , LANG_ARMENIAN  , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Armenian")
3571    LNG(wxLANGUAGE_ASSAMESE,                   "as"   , LANG_ASSAMESE  , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Assamese")
3572    LNG(wxLANGUAGE_AYMARA,                     "ay"   , 0              , 0                                 , wxLayout_LeftToRight, "Aymara")
3573    LNG(wxLANGUAGE_AZERI,                      "az"   , LANG_AZERI     , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Azeri")
3574    LNG(wxLANGUAGE_AZERI_CYRILLIC,             "az"   , LANG_AZERI     , SUBLANG_AZERI_CYRILLIC            , wxLayout_LeftToRight, "Azeri (Cyrillic)")
3575    LNG(wxLANGUAGE_AZERI_LATIN,                "az"   , LANG_AZERI     , SUBLANG_AZERI_LATIN               , wxLayout_LeftToRight, "Azeri (Latin)")
3576    LNG(wxLANGUAGE_BASHKIR,                    "ba"   , 0              , 0                                 , wxLayout_LeftToRight, "Bashkir")
3577    LNG(wxLANGUAGE_BASQUE,                     "eu_ES", LANG_BASQUE    , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Basque")
3578    LNG(wxLANGUAGE_BELARUSIAN,                 "be_BY", LANG_BELARUSIAN, SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Belarusian")
3579    LNG(wxLANGUAGE_BENGALI,                    "bn"   , LANG_BENGALI   , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Bengali")
3580    LNG(wxLANGUAGE_BHUTANI,                    "dz"   , 0              , 0                                 , wxLayout_LeftToRight, "Bhutani")
3581    LNG(wxLANGUAGE_BIHARI,                     "bh"   , 0              , 0                                 , wxLayout_LeftToRight, "Bihari")
3582    LNG(wxLANGUAGE_BISLAMA,                    "bi"   , 0              , 0                                 , wxLayout_LeftToRight, "Bislama")
3583    LNG(wxLANGUAGE_BRETON,                     "br"   , 0              , 0                                 , wxLayout_LeftToRight, "Breton")
3584    LNG(wxLANGUAGE_BULGARIAN,                  "bg_BG", LANG_BULGARIAN , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Bulgarian")
3585    LNG(wxLANGUAGE_BURMESE,                    "my"   , 0              , 0                                 , wxLayout_LeftToRight, "Burmese")
3586    LNG(wxLANGUAGE_CAMBODIAN,                  "km"   , 0              , 0                                 , wxLayout_LeftToRight, "Cambodian")
3587    LNG(wxLANGUAGE_CATALAN,                    "ca_ES", LANG_CATALAN   , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Catalan")
3588    LNG(wxLANGUAGE_CHINESE,                    "zh_TW", LANG_CHINESE   , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Chinese")
3589    LNG(wxLANGUAGE_CHINESE_SIMPLIFIED,         "zh_CN", LANG_CHINESE   , SUBLANG_CHINESE_SIMPLIFIED        , wxLayout_LeftToRight, "Chinese (Simplified)")
3590    LNG(wxLANGUAGE_CHINESE_TRADITIONAL,        "zh_TW", LANG_CHINESE   , SUBLANG_CHINESE_TRADITIONAL       , wxLayout_LeftToRight, "Chinese (Traditional)")
3591    LNG(wxLANGUAGE_CHINESE_HONGKONG,           "zh_HK", LANG_CHINESE   , SUBLANG_CHINESE_HONGKONG          , wxLayout_LeftToRight, "Chinese (Hongkong)")
3592    LNG(wxLANGUAGE_CHINESE_MACAU,              "zh_MO", LANG_CHINESE   , SUBLANG_CHINESE_MACAU             , wxLayout_LeftToRight, "Chinese (Macau)")
3593    LNG(wxLANGUAGE_CHINESE_SINGAPORE,          "zh_SG", LANG_CHINESE   , SUBLANG_CHINESE_SINGAPORE         , wxLayout_LeftToRight, "Chinese (Singapore)")
3594    LNG(wxLANGUAGE_CHINESE_TAIWAN,             "zh_TW", LANG_CHINESE   , SUBLANG_CHINESE_TRADITIONAL       , wxLayout_LeftToRight, "Chinese (Taiwan)")
3595    LNG(wxLANGUAGE_CORSICAN,                   "co"   , 0              , 0                                 , wxLayout_LeftToRight, "Corsican")
3596    LNG(wxLANGUAGE_CROATIAN,                   "hr_HR", LANG_CROATIAN  , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Croatian")
3597    LNG(wxLANGUAGE_CZECH,                      "cs_CZ", LANG_CZECH     , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Czech")
3598    LNG(wxLANGUAGE_DANISH,                     "da_DK", LANG_DANISH    , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Danish")
3599    LNG(wxLANGUAGE_DUTCH,                      "nl_NL", LANG_DUTCH     , SUBLANG_DUTCH                     , wxLayout_LeftToRight, "Dutch")
3600    LNG(wxLANGUAGE_DUTCH_BELGIAN,              "nl_BE", LANG_DUTCH     , SUBLANG_DUTCH_BELGIAN             , wxLayout_LeftToRight, "Dutch (Belgian)")
3601    LNG(wxLANGUAGE_ENGLISH,                    "en_GB", LANG_ENGLISH   , SUBLANG_ENGLISH_UK                , wxLayout_LeftToRight, "English")
3602    LNG(wxLANGUAGE_ENGLISH_UK,                 "en_GB", LANG_ENGLISH   , SUBLANG_ENGLISH_UK                , wxLayout_LeftToRight, "English (U.K.)")
3603    LNG(wxLANGUAGE_ENGLISH_US,                 "en_US", LANG_ENGLISH   , SUBLANG_ENGLISH_US                , wxLayout_LeftToRight, "English (U.S.)")
3604    LNG(wxLANGUAGE_ENGLISH_AUSTRALIA,          "en_AU", LANG_ENGLISH   , SUBLANG_ENGLISH_AUS               , wxLayout_LeftToRight, "English (Australia)")
3605    LNG(wxLANGUAGE_ENGLISH_BELIZE,             "en_BZ", LANG_ENGLISH   , SUBLANG_ENGLISH_BELIZE            , wxLayout_LeftToRight, "English (Belize)")
3606    LNG(wxLANGUAGE_ENGLISH_BOTSWANA,           "en_BW", 0              , 0                                 , wxLayout_LeftToRight, "English (Botswana)")
3607    LNG(wxLANGUAGE_ENGLISH_CANADA,             "en_CA", LANG_ENGLISH   , SUBLANG_ENGLISH_CAN               , wxLayout_LeftToRight, "English (Canada)")
3608    LNG(wxLANGUAGE_ENGLISH_CARIBBEAN,          "en_CB", LANG_ENGLISH   , SUBLANG_ENGLISH_CARIBBEAN         , wxLayout_LeftToRight, "English (Caribbean)")
3609    LNG(wxLANGUAGE_ENGLISH_DENMARK,            "en_DK", 0              , 0                                 , wxLayout_LeftToRight, "English (Denmark)")
3610    LNG(wxLANGUAGE_ENGLISH_EIRE,               "en_IE", LANG_ENGLISH   , SUBLANG_ENGLISH_EIRE              , wxLayout_LeftToRight, "English (Eire)")
3611    LNG(wxLANGUAGE_ENGLISH_JAMAICA,            "en_JM", LANG_ENGLISH   , SUBLANG_ENGLISH_JAMAICA           , wxLayout_LeftToRight, "English (Jamaica)")
3612    LNG(wxLANGUAGE_ENGLISH_NEW_ZEALAND,        "en_NZ", LANG_ENGLISH   , SUBLANG_ENGLISH_NZ                , wxLayout_LeftToRight, "English (New Zealand)")
3613    LNG(wxLANGUAGE_ENGLISH_PHILIPPINES,        "en_PH", LANG_ENGLISH   , SUBLANG_ENGLISH_PHILIPPINES       , wxLayout_LeftToRight, "English (Philippines)")
3614    LNG(wxLANGUAGE_ENGLISH_SOUTH_AFRICA,       "en_ZA", LANG_ENGLISH   , SUBLANG_ENGLISH_SOUTH_AFRICA      , wxLayout_LeftToRight, "English (South Africa)")
3615    LNG(wxLANGUAGE_ENGLISH_TRINIDAD,           "en_TT", LANG_ENGLISH   , SUBLANG_ENGLISH_TRINIDAD          , wxLayout_LeftToRight, "English (Trinidad)")
3616    LNG(wxLANGUAGE_ENGLISH_ZIMBABWE,           "en_ZW", LANG_ENGLISH   , SUBLANG_ENGLISH_ZIMBABWE          , wxLayout_LeftToRight, "English (Zimbabwe)")
3617    LNG(wxLANGUAGE_ESPERANTO,                  "eo"   , 0              , 0                                 , wxLayout_LeftToRight, "Esperanto")
3618    LNG(wxLANGUAGE_ESTONIAN,                   "et_EE", LANG_ESTONIAN  , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Estonian")
3619    LNG(wxLANGUAGE_FAEROESE,                   "fo_FO", LANG_FAEROESE  , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Faeroese")
3620    LNG(wxLANGUAGE_FARSI,                      "fa_IR", LANG_FARSI     , SUBLANG_DEFAULT                   , wxLayout_RightToLeft, "Farsi")
3621    LNG(wxLANGUAGE_FIJI,                       "fj"   , 0              , 0                                 , wxLayout_LeftToRight, "Fiji")
3622    LNG(wxLANGUAGE_FINNISH,                    "fi_FI", LANG_FINNISH   , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Finnish")
3623    LNG(wxLANGUAGE_FRENCH,                     "fr_FR", LANG_FRENCH    , SUBLANG_FRENCH                    , wxLayout_LeftToRight, "French")
3624    LNG(wxLANGUAGE_FRENCH_BELGIAN,             "fr_BE", LANG_FRENCH    , SUBLANG_FRENCH_BELGIAN            , wxLayout_LeftToRight, "French (Belgian)")
3625    LNG(wxLANGUAGE_FRENCH_CANADIAN,            "fr_CA", LANG_FRENCH    , SUBLANG_FRENCH_CANADIAN           , wxLayout_LeftToRight, "French (Canadian)")
3626    LNG(wxLANGUAGE_FRENCH_LUXEMBOURG,          "fr_LU", LANG_FRENCH    , SUBLANG_FRENCH_LUXEMBOURG         , wxLayout_LeftToRight, "French (Luxembourg)")
3627    LNG(wxLANGUAGE_FRENCH_MONACO,              "fr_MC", LANG_FRENCH    , SUBLANG_FRENCH_MONACO             , wxLayout_LeftToRight, "French (Monaco)")
3628    LNG(wxLANGUAGE_FRENCH_SWISS,               "fr_CH", LANG_FRENCH    , SUBLANG_FRENCH_SWISS              , wxLayout_LeftToRight, "French (Swiss)")
3629    LNG(wxLANGUAGE_FRISIAN,                    "fy"   , 0              , 0                                 , wxLayout_LeftToRight, "Frisian")
3630    LNG(wxLANGUAGE_GALICIAN,                   "gl_ES", 0              , 0                                 , wxLayout_LeftToRight, "Galician")
3631    LNG(wxLANGUAGE_GEORGIAN,                   "ka_GE", LANG_GEORGIAN  , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Georgian")
3632    LNG(wxLANGUAGE_GERMAN,                     "de_DE", LANG_GERMAN    , SUBLANG_GERMAN                    , wxLayout_LeftToRight, "German")
3633    LNG(wxLANGUAGE_GERMAN_AUSTRIAN,            "de_AT", LANG_GERMAN    , SUBLANG_GERMAN_AUSTRIAN           , wxLayout_LeftToRight, "German (Austrian)")
3634    LNG(wxLANGUAGE_GERMAN_BELGIUM,             "de_BE", 0              , 0                                 , wxLayout_LeftToRight, "German (Belgium)")
3635    LNG(wxLANGUAGE_GERMAN_LIECHTENSTEIN,       "de_LI", LANG_GERMAN    , SUBLANG_GERMAN_LIECHTENSTEIN      , wxLayout_LeftToRight, "German (Liechtenstein)")
3636    LNG(wxLANGUAGE_GERMAN_LUXEMBOURG,          "de_LU", LANG_GERMAN    , SUBLANG_GERMAN_LUXEMBOURG         , wxLayout_LeftToRight, "German (Luxembourg)")
3637    LNG(wxLANGUAGE_GERMAN_SWISS,               "de_CH", LANG_GERMAN    , SUBLANG_GERMAN_SWISS              , wxLayout_LeftToRight, "German (Swiss)")
3638    LNG(wxLANGUAGE_GREEK,                      "el_GR", LANG_GREEK     , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Greek")
3639    LNG(wxLANGUAGE_GREENLANDIC,                "kl_GL", 0              , 0                                 , wxLayout_LeftToRight, "Greenlandic")
3640    LNG(wxLANGUAGE_GUARANI,                    "gn"   , 0              , 0                                 , wxLayout_LeftToRight, "Guarani")
3641    LNG(wxLANGUAGE_GUJARATI,                   "gu"   , LANG_GUJARATI  , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Gujarati")
3642    LNG(wxLANGUAGE_HAUSA,                      "ha"   , 0              , 0                                 , wxLayout_LeftToRight, "Hausa")
3643    LNG(wxLANGUAGE_HEBREW,                     "he_IL", LANG_HEBREW    , SUBLANG_DEFAULT                   , wxLayout_RightToLeft, "Hebrew")
3644    LNG(wxLANGUAGE_HINDI,                      "hi_IN", LANG_HINDI     , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Hindi")
3645    LNG(wxLANGUAGE_HUNGARIAN,                  "hu_HU", LANG_HUNGARIAN , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Hungarian")
3646    LNG(wxLANGUAGE_ICELANDIC,                  "is_IS", LANG_ICELANDIC , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Icelandic")
3647    LNG(wxLANGUAGE_INDONESIAN,                 "id_ID", LANG_INDONESIAN, SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Indonesian")
3648    LNG(wxLANGUAGE_INTERLINGUA,                "ia"   , 0              , 0                                 , wxLayout_LeftToRight, "Interlingua")
3649    LNG(wxLANGUAGE_INTERLINGUE,                "ie"   , 0              , 0                                 , wxLayout_LeftToRight, "Interlingue")
3650    LNG(wxLANGUAGE_INUKTITUT,                  "iu"   , 0              , 0                                 , wxLayout_LeftToRight, "Inuktitut")
3651    LNG(wxLANGUAGE_INUPIAK,                    "ik"   , 0              , 0                                 , wxLayout_LeftToRight, "Inupiak")
3652    LNG(wxLANGUAGE_IRISH,                      "ga_IE", 0              , 0                                 , wxLayout_LeftToRight, "Irish")
3653    LNG(wxLANGUAGE_ITALIAN,                    "it_IT", LANG_ITALIAN   , SUBLANG_ITALIAN                   , wxLayout_LeftToRight, "Italian")
3654    LNG(wxLANGUAGE_ITALIAN_SWISS,              "it_CH", LANG_ITALIAN   , SUBLANG_ITALIAN_SWISS             , wxLayout_LeftToRight, "Italian (Swiss)")
3655    LNG(wxLANGUAGE_JAPANESE,                   "ja_JP", LANG_JAPANESE  , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Japanese")
3656    LNG(wxLANGUAGE_JAVANESE,                   "jw"   , 0              , 0                                 , wxLayout_LeftToRight, "Javanese")
3657    LNG(wxLANGUAGE_KANNADA,                    "kn"   , LANG_KANNADA   , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Kannada")
3658    LNG(wxLANGUAGE_KASHMIRI,                   "ks"   , LANG_KASHMIRI  , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Kashmiri")
3659    LNG(wxLANGUAGE_KASHMIRI_INDIA,             "ks_IN", LANG_KASHMIRI  , SUBLANG_KASHMIRI_INDIA            , wxLayout_LeftToRight, "Kashmiri (India)")
3660    LNG(wxLANGUAGE_KAZAKH,                     "kk"   , LANG_KAZAK     , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Kazakh")
3661    LNG(wxLANGUAGE_KERNEWEK,                   "kw_GB", 0              , 0                                 , wxLayout_LeftToRight, "Kernewek")
3662    LNG(wxLANGUAGE_KINYARWANDA,                "rw"   , 0              , 0                                 , wxLayout_LeftToRight, "Kinyarwanda")
3663    LNG(wxLANGUAGE_KIRGHIZ,                    "ky"   , 0              , 0                                 , wxLayout_LeftToRight, "Kirghiz")
3664    LNG(wxLANGUAGE_KIRUNDI,                    "rn"   , 0              , 0                                 , wxLayout_LeftToRight, "Kirundi")
3665    LNG(wxLANGUAGE_KONKANI,                    ""     , LANG_KONKANI   , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Konkani")
3666    LNG(wxLANGUAGE_KOREAN,                     "ko_KR", LANG_KOREAN    , SUBLANG_KOREAN                    , wxLayout_LeftToRight, "Korean")
3667    LNG(wxLANGUAGE_KURDISH,                    "ku_TR", 0              , 0                                 , wxLayout_LeftToRight, "Kurdish")
3668    LNG(wxLANGUAGE_LAOTHIAN,                   "lo"   , 0              , 0                                 , wxLayout_LeftToRight, "Laothian")
3669    LNG(wxLANGUAGE_LATIN,                      "la"   , 0              , 0                                 , wxLayout_LeftToRight, "Latin")
3670    LNG(wxLANGUAGE_LATVIAN,                    "lv_LV", LANG_LATVIAN   , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Latvian")
3671    LNG(wxLANGUAGE_LINGALA,                    "ln"   , 0              , 0                                 , wxLayout_LeftToRight, "Lingala")
3672    LNG(wxLANGUAGE_LITHUANIAN,                 "lt_LT", LANG_LITHUANIAN, SUBLANG_LITHUANIAN                , wxLayout_LeftToRight, "Lithuanian")
3673    LNG(wxLANGUAGE_MACEDONIAN,                 "mk_MK", LANG_MACEDONIAN, SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Macedonian")
3674    LNG(wxLANGUAGE_MALAGASY,                   "mg"   , 0              , 0                                 , wxLayout_LeftToRight, "Malagasy")
3675    LNG(wxLANGUAGE_MALAY,                      "ms_MY", LANG_MALAY     , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Malay")
3676    LNG(wxLANGUAGE_MALAYALAM,                  "ml"   , LANG_MALAYALAM , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Malayalam")
3677    LNG(wxLANGUAGE_MALAY_BRUNEI_DARUSSALAM,    "ms_BN", LANG_MALAY     , SUBLANG_MALAY_BRUNEI_DARUSSALAM   , wxLayout_LeftToRight, "Malay (Brunei Darussalam)")
3678    LNG(wxLANGUAGE_MALAY_MALAYSIA,             "ms_MY", LANG_MALAY     , SUBLANG_MALAY_MALAYSIA            , wxLayout_LeftToRight, "Malay (Malaysia)")
3679    LNG(wxLANGUAGE_MALTESE,                    "mt_MT", 0              , 0                                 , wxLayout_LeftToRight, "Maltese")
3680    LNG(wxLANGUAGE_MANIPURI,                   ""     , LANG_MANIPURI  , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Manipuri")
3681    LNG(wxLANGUAGE_MAORI,                      "mi"   , 0              , 0                                 , wxLayout_LeftToRight, "Maori")
3682    LNG(wxLANGUAGE_MARATHI,                    "mr_IN", LANG_MARATHI   , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Marathi")
3683    LNG(wxLANGUAGE_MOLDAVIAN,                  "mo"   , 0              , 0                                 , wxLayout_LeftToRight, "Moldavian")
3684    LNG(wxLANGUAGE_MONGOLIAN,                  "mn"   , 0              , 0                                 , wxLayout_LeftToRight, "Mongolian")
3685    LNG(wxLANGUAGE_NAURU,                      "na"   , 0              , 0                                 , wxLayout_LeftToRight, "Nauru")
3686    LNG(wxLANGUAGE_NEPALI,                     "ne_NP", LANG_NEPALI    , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Nepali")
3687    LNG(wxLANGUAGE_NEPALI_INDIA,               "ne_IN", LANG_NEPALI    , SUBLANG_NEPALI_INDIA              , wxLayout_LeftToRight, "Nepali (India)")
3688    LNG(wxLANGUAGE_NORWEGIAN_BOKMAL,           "nb_NO", LANG_NORWEGIAN , SUBLANG_NORWEGIAN_BOKMAL          , wxLayout_LeftToRight, "Norwegian (Bokmal)")
3689    LNG(wxLANGUAGE_NORWEGIAN_NYNORSK,          "nn_NO", LANG_NORWEGIAN , SUBLANG_NORWEGIAN_NYNORSK         , wxLayout_LeftToRight, "Norwegian (Nynorsk)")
3690    LNG(wxLANGUAGE_OCCITAN,                    "oc"   , 0              , 0                                 , wxLayout_LeftToRight, "Occitan")
3691    LNG(wxLANGUAGE_ORIYA,                      "or"   , LANG_ORIYA     , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Oriya")
3692    LNG(wxLANGUAGE_OROMO,                      "om"   , 0              , 0                                 , wxLayout_LeftToRight, "(Afan) Oromo")
3693    LNG(wxLANGUAGE_PASHTO,                     "ps"   , 0              , 0                                 , wxLayout_LeftToRight, "Pashto, Pushto")
3694    LNG(wxLANGUAGE_POLISH,                     "pl_PL", LANG_POLISH    , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Polish")
3695    LNG(wxLANGUAGE_PORTUGUESE,                 "pt_PT", LANG_PORTUGUESE, SUBLANG_PORTUGUESE                , wxLayout_LeftToRight, "Portuguese")
3696    LNG(wxLANGUAGE_PORTUGUESE_BRAZILIAN,       "pt_BR", LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN      , wxLayout_LeftToRight, "Portuguese (Brazilian)")
3697    LNG(wxLANGUAGE_PUNJABI,                    "pa"   , LANG_PUNJABI   , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Punjabi")
3698    LNG(wxLANGUAGE_QUECHUA,                    "qu"   , 0              , 0                                 , wxLayout_LeftToRight, "Quechua")
3699    LNG(wxLANGUAGE_RHAETO_ROMANCE,             "rm"   , 0              , 0                                 , wxLayout_LeftToRight, "Rhaeto-Romance")
3700    LNG(wxLANGUAGE_ROMANIAN,                   "ro_RO", LANG_ROMANIAN  , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Romanian")
3701    LNG(wxLANGUAGE_RUSSIAN,                    "ru_RU", LANG_RUSSIAN   , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Russian")
3702    LNG(wxLANGUAGE_RUSSIAN_UKRAINE,            "ru_UA", 0              , 0                                 , wxLayout_LeftToRight, "Russian (Ukraine)")
3703    LNG(wxLANGUAGE_SAMI,                       "se_NO", LANG_SAMI      , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Northern Sami")
3704    LNG(wxLANGUAGE_SAMOAN,                     "sm"   , 0              , 0                                 , wxLayout_LeftToRight, "Samoan")
3705    LNG(wxLANGUAGE_SANGHO,                     "sg"   , 0              , 0                                 , wxLayout_LeftToRight, "Sangho")
3706    LNG(wxLANGUAGE_SANSKRIT,                   "sa"   , LANG_SANSKRIT  , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Sanskrit")
3707    LNG(wxLANGUAGE_SCOTS_GAELIC,               "gd"   , 0              , 0                                 , wxLayout_LeftToRight, "Scots Gaelic")
3708    LNG(wxLANGUAGE_SERBIAN,                    "sr_RS", LANG_SERBIAN   , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Serbian")
3709    LNG(wxLANGUAGE_SERBIAN_CYRILLIC,           "sr_RS", LANG_SERBIAN   , SUBLANG_SERBIAN_CYRILLIC          , wxLayout_LeftToRight, "Serbian (Cyrillic)")
3710    LNG(wxLANGUAGE_SERBIAN_LATIN,              "sr_RS@latin", LANG_SERBIAN   , SUBLANG_SERBIAN_LATIN             , wxLayout_LeftToRight, "Serbian (Latin)")
3711    LNG(wxLANGUAGE_SERBIAN_CYRILLIC,           "sr_YU", LANG_SERBIAN   , SUBLANG_SERBIAN_CYRILLIC          , wxLayout_LeftToRight, "Serbian (Cyrillic)")
3712    LNG(wxLANGUAGE_SERBIAN_LATIN,              "sr_YU@latin", LANG_SERBIAN   , SUBLANG_SERBIAN_LATIN             , wxLayout_LeftToRight, "Serbian (Latin)")
3713    LNG(wxLANGUAGE_SERBO_CROATIAN,             "sh"   , 0              , 0                                 , wxLayout_LeftToRight, "Serbo-Croatian")
3714    LNG(wxLANGUAGE_SESOTHO,                    "st"   , 0              , 0                                 , wxLayout_LeftToRight, "Sesotho")
3715    LNG(wxLANGUAGE_SETSWANA,                   "tn"   , 0              , 0                                 , wxLayout_LeftToRight, "Setswana")
3716    LNG(wxLANGUAGE_SHONA,                      "sn"   , 0              , 0                                 , wxLayout_LeftToRight, "Shona")
3717    LNG(wxLANGUAGE_SINDHI,                     "sd"   , LANG_SINDHI    , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Sindhi")
3718    LNG(wxLANGUAGE_SINHALESE,                  "si"   , 0              , 0                                 , wxLayout_LeftToRight, "Sinhalese")
3719    LNG(wxLANGUAGE_SISWATI,                    "ss"   , 0              , 0                                 , wxLayout_LeftToRight, "Siswati")
3720    LNG(wxLANGUAGE_SLOVAK,                     "sk_SK", LANG_SLOVAK    , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Slovak")
3721    LNG(wxLANGUAGE_SLOVENIAN,                  "sl_SI", LANG_SLOVENIAN , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Slovenian")
3722    LNG(wxLANGUAGE_SOMALI,                     "so"   , 0              , 0                                 , wxLayout_LeftToRight, "Somali")
3723    LNG(wxLANGUAGE_SPANISH,                    "es_ES", LANG_SPANISH   , SUBLANG_SPANISH                   , wxLayout_LeftToRight, "Spanish")
3724    LNG(wxLANGUAGE_SPANISH_ARGENTINA,          "es_AR", LANG_SPANISH   , SUBLANG_SPANISH_ARGENTINA         , wxLayout_LeftToRight, "Spanish (Argentina)")
3725    LNG(wxLANGUAGE_SPANISH_BOLIVIA,            "es_BO", LANG_SPANISH   , SUBLANG_SPANISH_BOLIVIA           , wxLayout_LeftToRight, "Spanish (Bolivia)")
3726    LNG(wxLANGUAGE_SPANISH_CHILE,              "es_CL", LANG_SPANISH   , SUBLANG_SPANISH_CHILE             , wxLayout_LeftToRight, "Spanish (Chile)")
3727    LNG(wxLANGUAGE_SPANISH_COLOMBIA,           "es_CO", LANG_SPANISH   , SUBLANG_SPANISH_COLOMBIA          , wxLayout_LeftToRight, "Spanish (Colombia)")
3728    LNG(wxLANGUAGE_SPANISH_COSTA_RICA,         "es_CR", LANG_SPANISH   , SUBLANG_SPANISH_COSTA_RICA        , wxLayout_LeftToRight, "Spanish (Costa Rica)")
3729    LNG(wxLANGUAGE_SPANISH_DOMINICAN_REPUBLIC, "es_DO", LANG_SPANISH   , SUBLANG_SPANISH_DOMINICAN_REPUBLIC, wxLayout_LeftToRight, "Spanish (Dominican republic)")
3730    LNG(wxLANGUAGE_SPANISH_ECUADOR,            "es_EC", LANG_SPANISH   , SUBLANG_SPANISH_ECUADOR           , wxLayout_LeftToRight, "Spanish (Ecuador)")
3731    LNG(wxLANGUAGE_SPANISH_EL_SALVADOR,        "es_SV", LANG_SPANISH   , SUBLANG_SPANISH_EL_SALVADOR       , wxLayout_LeftToRight, "Spanish (El Salvador)")
3732    LNG(wxLANGUAGE_SPANISH_GUATEMALA,          "es_GT", LANG_SPANISH   , SUBLANG_SPANISH_GUATEMALA         , wxLayout_LeftToRight, "Spanish (Guatemala)")
3733    LNG(wxLANGUAGE_SPANISH_HONDURAS,           "es_HN", LANG_SPANISH   , SUBLANG_SPANISH_HONDURAS          , wxLayout_LeftToRight, "Spanish (Honduras)")
3734    LNG(wxLANGUAGE_SPANISH_MEXICAN,            "es_MX", LANG_SPANISH   , SUBLANG_SPANISH_MEXICAN           , wxLayout_LeftToRight, "Spanish (Mexican)")
3735    LNG(wxLANGUAGE_SPANISH_MODERN,             "es_ES", LANG_SPANISH   , SUBLANG_SPANISH_MODERN            , wxLayout_LeftToRight, "Spanish (Modern)")
3736    LNG(wxLANGUAGE_SPANISH_NICARAGUA,          "es_NI", LANG_SPANISH   , SUBLANG_SPANISH_NICARAGUA         , wxLayout_LeftToRight, "Spanish (Nicaragua)")
3737    LNG(wxLANGUAGE_SPANISH_PANAMA,             "es_PA", LANG_SPANISH   , SUBLANG_SPANISH_PANAMA            , wxLayout_LeftToRight, "Spanish (Panama)")
3738    LNG(wxLANGUAGE_SPANISH_PARAGUAY,           "es_PY", LANG_SPANISH   , SUBLANG_SPANISH_PARAGUAY          , wxLayout_LeftToRight, "Spanish (Paraguay)")
3739    LNG(wxLANGUAGE_SPANISH_PERU,               "es_PE", LANG_SPANISH   , SUBLANG_SPANISH_PERU              , wxLayout_LeftToRight, "Spanish (Peru)")
3740    LNG(wxLANGUAGE_SPANISH_PUERTO_RICO,        "es_PR", LANG_SPANISH   , SUBLANG_SPANISH_PUERTO_RICO       , wxLayout_LeftToRight, "Spanish (Puerto Rico)")
3741    LNG(wxLANGUAGE_SPANISH_URUGUAY,            "es_UY", LANG_SPANISH   , SUBLANG_SPANISH_URUGUAY           , wxLayout_LeftToRight, "Spanish (Uruguay)")
3742    LNG(wxLANGUAGE_SPANISH_US,                 "es_US", 0              , 0                                 , wxLayout_LeftToRight, "Spanish (U.S.)")
3743    LNG(wxLANGUAGE_SPANISH_VENEZUELA,          "es_VE", LANG_SPANISH   , SUBLANG_SPANISH_VENEZUELA         , wxLayout_LeftToRight, "Spanish (Venezuela)")
3744    LNG(wxLANGUAGE_SUNDANESE,                  "su"   , 0              , 0                                 , wxLayout_LeftToRight, "Sundanese")
3745    LNG(wxLANGUAGE_SWAHILI,                    "sw_KE", LANG_SWAHILI   , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Swahili")
3746    LNG(wxLANGUAGE_SWEDISH,                    "sv_SE", LANG_SWEDISH   , SUBLANG_SWEDISH                   , wxLayout_LeftToRight, "Swedish")
3747    LNG(wxLANGUAGE_SWEDISH_FINLAND,            "sv_FI", LANG_SWEDISH   , SUBLANG_SWEDISH_FINLAND           , wxLayout_LeftToRight, "Swedish (Finland)")
3748    LNG(wxLANGUAGE_TAGALOG,                    "tl_PH", 0              , 0                                 , wxLayout_LeftToRight, "Tagalog")
3749    LNG(wxLANGUAGE_TAJIK,                      "tg"   , 0              , 0                                 , wxLayout_LeftToRight, "Tajik")
3750    LNG(wxLANGUAGE_TAMIL,                      "ta"   , LANG_TAMIL     , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Tamil")
3751    LNG(wxLANGUAGE_TATAR,                      "tt"   , LANG_TATAR     , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Tatar")
3752    LNG(wxLANGUAGE_TELUGU,                     "te"   , LANG_TELUGU    , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Telugu")
3753    LNG(wxLANGUAGE_THAI,                       "th_TH", LANG_THAI      , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Thai")
3754    LNG(wxLANGUAGE_TIBETAN,                    "bo"   , 0              , 0                                 , wxLayout_LeftToRight, "Tibetan")
3755    LNG(wxLANGUAGE_TIGRINYA,                   "ti"   , 0              , 0                                 , wxLayout_LeftToRight, "Tigrinya")
3756    LNG(wxLANGUAGE_TONGA,                      "to"   , 0              , 0                                 , wxLayout_LeftToRight, "Tonga")
3757    LNG(wxLANGUAGE_TSONGA,                     "ts"   , 0              , 0                                 , wxLayout_LeftToRight, "Tsonga")
3758    LNG(wxLANGUAGE_TURKISH,                    "tr_TR", LANG_TURKISH   , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Turkish")
3759    LNG(wxLANGUAGE_TURKMEN,                    "tk"   , 0              , 0                                 , wxLayout_LeftToRight, "Turkmen")
3760    LNG(wxLANGUAGE_TWI,                        "tw"   , 0              , 0                                 , wxLayout_LeftToRight, "Twi")
3761    LNG(wxLANGUAGE_UIGHUR,                     "ug"   , 0              , 0                                 , wxLayout_LeftToRight, "Uighur")
3762    LNG(wxLANGUAGE_UKRAINIAN,                  "uk_UA", LANG_UKRAINIAN , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Ukrainian")
3763    LNG(wxLANGUAGE_URDU,                       "ur"   , LANG_URDU      , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Urdu")
3764    LNG(wxLANGUAGE_URDU_INDIA,                 "ur_IN", LANG_URDU      , SUBLANG_URDU_INDIA                , wxLayout_LeftToRight, "Urdu (India)")
3765    LNG(wxLANGUAGE_URDU_PAKISTAN,              "ur_PK", LANG_URDU      , SUBLANG_URDU_PAKISTAN             , wxLayout_LeftToRight, "Urdu (Pakistan)")
3766    LNG(wxLANGUAGE_UZBEK,                      "uz"   , LANG_UZBEK     , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Uzbek")
3767    LNG(wxLANGUAGE_UZBEK_CYRILLIC,             "uz"   , LANG_UZBEK     , SUBLANG_UZBEK_CYRILLIC            , wxLayout_LeftToRight, "Uzbek (Cyrillic)")
3768    LNG(wxLANGUAGE_UZBEK_LATIN,                "uz"   , LANG_UZBEK     , SUBLANG_UZBEK_LATIN               , wxLayout_LeftToRight, "Uzbek (Latin)")
3769    LNG(wxLANGUAGE_VALENCIAN,                  "ca_ES@valencia", LANG_VALENCIAN , SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Valencian")
3770    LNG(wxLANGUAGE_VIETNAMESE,                 "vi_VN", LANG_VIETNAMESE, SUBLANG_DEFAULT                   , wxLayout_LeftToRight, "Vietnamese")
3771    LNG(wxLANGUAGE_VOLAPUK,                    "vo"   , 0              , 0                                 , wxLayout_LeftToRight, "Volapuk")
3772    LNG(wxLANGUAGE_WELSH,                      "cy"   , 0              , 0                                 , wxLayout_LeftToRight, "Welsh")
3773    LNG(wxLANGUAGE_WOLOF,                      "wo"   , 0              , 0                                 , wxLayout_LeftToRight, "Wolof")
3774    LNG(wxLANGUAGE_XHOSA,                      "xh"   , 0              , 0                                 , wxLayout_LeftToRight, "Xhosa")
3775    LNG(wxLANGUAGE_YIDDISH,                    "yi"   , 0              , 0                                 , wxLayout_LeftToRight, "Yiddish")
3776    LNG(wxLANGUAGE_YORUBA,                     "yo"   , 0              , 0                                 , wxLayout_LeftToRight, "Yoruba")
3777    LNG(wxLANGUAGE_ZHUANG,                     "za"   , 0              , 0                                 , wxLayout_LeftToRight, "Zhuang")
3778    LNG(wxLANGUAGE_ZULU,                       "zu"   , 0              , 0                                 , wxLayout_LeftToRight, "Zulu")
3779 }
3780 #undef LNG
3781 
3782 // --- --- --- generated code ends here --- --- ---
3783 
3784 #endif // wxUSE_INTL
3785