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!
88typedef wxUint8 size_t8;
89typedef wxUint32 size_t32;
90
91// ----------------------------------------------------------------------------
92// constants
93// ----------------------------------------------------------------------------
94
95// magic number identifying the .mo format file
96const size_t32 MSGCATALOG_MAGIC    = 0x950412de;
97const size_t32 MSGCATALOG_MAGIC_SW = 0xde120495;
98
99// the constants describing the format of lang_LANG locale string
100static const size_t LEN_LANG = 2;
101static const size_t LEN_SUBLANG = 2;
102static 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
113class NoTransErr
114{
115public:
116    NoTransErr() { ms_suppressCount++; }
117   ~NoTransErr() { ms_suppressCount--;  }
118
119   static bool Suppress() { return ms_suppressCount > 0; }
120
121private:
122   static size_t ms_suppressCount;
123};
124
125size_t NoTransErr::ms_suppressCount = 0;
126
127#else // !Debug
128
129class NoTransErr
130{
131public:
132    NoTransErr() { }
133   ~NoTransErr() { }
134};
135
136#endif // Debug/!Debug
137
138static wxLocale *wxSetLocale(wxLocale *pLocale);
139
140// helper functions of GetSystemLanguage()
141#ifdef __UNIX__
142
143// get just the language part
144static inline wxString ExtractLang(const wxString& langFull)
145{
146    return langFull.Left(LEN_LANG);
147}
148
149// get everything else (including the leading '_')
150static 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
165Expression:
166    LogicalOrExpression '?' Expression ':' Expression
167    LogicalOrExpression
168
169LogicalOrExpression:
170    LogicalAndExpression "||" LogicalOrExpression   // to (a || b) || c
171    LogicalAndExpression
172
173LogicalAndExpression:
174    EqualityExpression "&&" LogicalAndExpression    // to (a && b) && c
175    EqualityExpression
176
177EqualityExpression:
178    RelationalExpression "==" RelationalExperession
179    RelationalExpression "!=" RelationalExperession
180    RelationalExpression
181
182RelationalExpression:
183    MultiplicativeExpression '>' MultiplicativeExpression
184    MultiplicativeExpression '<' MultiplicativeExpression
185    MultiplicativeExpression ">=" MultiplicativeExpression
186    MultiplicativeExpression "<=" MultiplicativeExpression
187    MultiplicativeExpression
188
189MultiplicativeExpression:
190    PmExpression '%' PmExpression
191    PmExpression
192
193PmExpression:
194    N
195    Number
196    '(' Expression ')'
197*/
198
199class wxPluralFormsToken
200{
201public:
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    };
210    Type type() const { return m_type; }
211    void setType(Type type) { m_type = type; }
212    // for T_NUMBER only
213    typedef int Number;
214    Number number() const { return m_number; }
215    void setNumber(Number num) { m_number = num; }
216private:
217    Type m_type;
218    Number m_number;
219};
220
221
222class wxPluralFormsScanner
223{
224public:
225    wxPluralFormsScanner(const char* s);
226    const wxPluralFormsToken& token() const { return m_token; }
227    bool nextToken();  // returns false if error
228private:
229    const char* m_s;
230    wxPluralFormsToken m_token;
231};
232
233wxPluralFormsScanner::wxPluralFormsScanner(const char* s) : m_s(s)
234{
235    nextToken();
236}
237
238bool 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
366class wxPluralFormsNode;
367
368// NB: Can't use wxDEFINE_SCOPED_PTR_TYPE because wxPluralFormsNode is not
369//     fully defined yet:
370class wxPluralFormsNodePtr
371{
372public:
373    wxPluralFormsNodePtr(wxPluralFormsNode *p = NULL) : m_p(p) {}
374    ~wxPluralFormsNodePtr();
375    wxPluralFormsNode& operator*() const { return *m_p; }
376    wxPluralFormsNode* operator->() const { return m_p; }
377    wxPluralFormsNode* get() const { return m_p; }
378    wxPluralFormsNode* release();
379    void reset(wxPluralFormsNode *p);
380
381private:
382    wxPluralFormsNode *m_p;
383};
384
385class wxPluralFormsNode
386{
387public:
388    wxPluralFormsNode(const wxPluralFormsToken& token) : m_token(token) {}
389    const wxPluralFormsToken& token() const { return m_token; }
390    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
396private:
397    wxPluralFormsToken m_token;
398    wxPluralFormsNodePtr m_nodes[3];
399};
400
401wxPluralFormsNodePtr::~wxPluralFormsNodePtr()
402{
403    delete m_p;
404}
405wxPluralFormsNode* wxPluralFormsNodePtr::release()
406{
407    wxPluralFormsNode *p = m_p;
408    m_p = NULL;
409    return p;
410}
411void wxPluralFormsNodePtr::reset(wxPluralFormsNode *p)
412{
413    if (p != m_p)
414    {
415        delete m_p;
416        m_p = p;
417    }
418}
419
420
421void wxPluralFormsNode::setNode(size_t i, wxPluralFormsNode* n)
422{
423    m_nodes[i].reset(n);
424}
425
426wxPluralFormsNode*  wxPluralFormsNode::releaseNode(size_t i)
427{
428    return m_nodes[i].release();
429}
430
431wxPluralFormsToken::Number
432wxPluralFormsNode::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
481class wxPluralFormsCalculator
482{
483public:
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
494    ~wxPluralFormsCalculator() {}
495
496    void  init(wxPluralFormsToken::Number nplurals, wxPluralFormsNode* plural);
497
498private:
499    wxPluralFormsToken::Number m_nplurals;
500    wxPluralFormsNodePtr m_plural;
501};
502
503wxDEFINE_SCOPED_PTR_TYPE(wxPluralFormsCalculator)
504
505void wxPluralFormsCalculator::init(wxPluralFormsToken::Number nplurals,
506                                   wxPluralFormsNode* plural)
507{
508    m_nplurals = nplurals;
509    m_plural.reset(plural);
510}
511
512int 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
527class wxPluralFormsParser
528{
529public:
530    wxPluralFormsParser(wxPluralFormsScanner& scanner) : m_scanner(scanner) {}
531    bool parse(wxPluralFormsCalculator& rCalculator);
532
533private:
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
549bool 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
589wxPluralFormsNode* 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
604const wxPluralFormsToken& wxPluralFormsParser::token() const
605{
606    return m_scanner.token();
607}
608
609bool wxPluralFormsParser::nextToken()
610{
611    if (!m_scanner.nextToken())
612        return false;
613    return true;
614}
615
616wxPluralFormsNode* 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
655wxPluralFormsNode*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
691wxPluralFormsNode* 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
729wxPluralFormsNode* 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
755wxPluralFormsNode* 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
783wxPluralFormsNode* 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
808wxPluralFormsNode* 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
847wxPluralFormsCalculator* 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
871WX_DECLARE_EXPORTED_STRING_HASH_MAP(wxString, wxMessagesHash);
872
873class wxMsgCatalogFile
874{
875public:
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
891    wxString GetCharset() const { return m_charset; }
892
893private:
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
930    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
937    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
964class wxMsgCatalog
965{
966public:
967#if !wxUSE_UNICODE
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
977    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
985private:
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
1003static wxArrayString gs_searchPrefixes;
1004
1005// ============================================================================
1006// implementation
1007// ============================================================================
1008
1009// ----------------------------------------------------------------------------
1010// wxMsgCatalogFile class
1011// ----------------------------------------------------------------------------
1012
1013wxMsgCatalogFile::wxMsgCatalogFile()
1014{
1015    m_pData = NULL;
1016    m_nSize = 0;
1017}
1018
1019wxMsgCatalogFile::~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
1026static
1027wxString 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
1053static 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
1113bool 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
1272void 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
1421wxMsgCatalog::~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
1437bool 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
1470const 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"
1500WX_DECLARE_EXPORTED_OBJARRAY(wxLanguageInfo, wxLanguageInfoArray);
1501WX_DEFINE_OBJARRAY(wxLanguageInfoArray)
1502
1503wxLanguageInfoArray *wxLocale::ms_languagesDB = NULL;
1504
1505/*static*/ void wxLocale::CreateLanguagesDB()
1506{
1507    if (ms_languagesDB == NULL)
1508    {
1509        ms_languagesDB = new wxLanguageInfoArray;
1510        InitLanguagesDB();
1511    }
1512}
1513
1514/*static*/ void wxLocale::DestroyLanguagesDB()
1515{
1516    delete ms_languagesDB;
1517    ms_languagesDB = NULL;
1518}
1519
1520
1521void 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
1533bool 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"));
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__)
1619static 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
1650bool 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
1895void 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
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 */
2384wxString 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 */
2442wxFontEncoding 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 */
2525void wxLocale::AddLanguage(const wxLanguageInfo& info)
2526{
2527    CreateLanguagesDB();
2528    ms_languagesDB->Add(info);
2529}
2530
2531/* static */
2532const 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 */
2556wxString 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 */
2566const 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
2601wxString 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
2612wxLocale::~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
2633const wxChar *wxLocale::GetString(const wxChar *szOrigString,
2634                                  const wxChar *szDomain) const
2635{
2636    return GetString(szOrigString, szOrigString, size_t(-1), szDomain);
2637}
2638
2639const 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
2694wxString 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
2747wxMsgCatalog *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 */
2762bool 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
2799bool wxLocale::IsLoaded(const wxChar *szDomain) const
2800{
2801  return FindCatalog(szDomain) != NULL;
2802}
2803
2804// add a catalog to our linked list
2805bool wxLocale::AddCatalog(const wxChar *szDomain)
2806{
2807    return AddCatalog(szDomain, wxLANGUAGE_ENGLISH_US, NULL);
2808}
2809
2810// add a catalog to our linked list
2811bool 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 */
2857wxString 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 */
2909wxString 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 */
2950wxString 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
2994static wxLocale *g_pLocale = NULL;
2995
2996wxLocale *wxGetLocale()
2997{
2998  return g_pLocale;
2999}
3000
3001wxLocale *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
3014class wxLocaleModule: public wxModule
3015{
3016    DECLARE_DYNAMIC_CLASS(wxLocaleModule)
3017    public:
3018        wxLocaleModule() {}
3019        bool OnInit() { return true; }
3020        void OnExit() { wxLocale::DestroyLanguagesDB(); }
3021};
3022
3023IMPLEMENT_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
3542void 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