1
////////////////////////////////////////////////////////////////////////////
2
// NoteCase notes manager project <http://notecase.sf.net>
4
// This code is licensed under BSD license.See "license.txt" for more details.
6
// File: Class for handling internationalisation issues (message catalogs)
7
////////////////////////////////////////////////////////////////////////////
10
#pragma warning(disable: 4996) //ignore deprecated functions warning
13
#include "../config.h"
14
#include "GuiLanguage.h"
22
#include "../lib/EnumDirectory.h"
25
#include <io.h> //access
27
#define access _access
29
#include <libgen.h> //basename on Archlinux
32
#if defined (__FreeBSD__) || defined (__APPLE__)
33
#include <libgen.h> //basename
36
extern GuiLanguage g_lang;
38
bool OnDirEnum(const char *szDir, void *data);
39
#define ARRAY_COUNT(x) (sizeof(x)/sizeof(x[0]))
42
//define dummy versions of Windows language IDs
43
#define LANG_AFRIKAANS 0
44
#define LANG_ALBANIAN 0
45
#define LANG_AMHARIC 0
47
#define LANG_ARMENIAN 0
49
#define LANG_BELARUSIAN 0
50
#define LANG_BENGALI 0
51
#define LANG_BULGARIAN 0
52
#define LANG_CATALAN 0
53
#define LANG_CROATIAN 0
57
#define LANG_ENGLISH 0
58
#define LANG_ESTONIAN 0
59
#define LANG_ESPERANTO 0
62
#define LANG_FINNISH 0
63
#define LANG_GEORGIAN 0
68
#define LANG_HUNGARIAN 0
69
#define LANG_ICELANDIC 0
70
#define LANG_INDONESIAN 0
71
#define LANG_ITALIAN 0
72
#define LANG_JAPANESE 0
74
#define LANG_LATVIAN 0
75
#define LANG_LITHUANIAN 0
76
#define LANG_MACEDONIAN 0
77
#define LANG_MONGOLIAN 0
79
#define LANG_NORWEGIAN 0
81
#define LANG_PORTUGUESE 0
82
#define LANG_ROMANIAN 0
83
#define LANG_RUSSIAN 0
84
#define LANG_SERBIAN 0
86
#define LANG_SLOVENIAN 0
87
#define LANG_SPANISH 0
88
#define LANG_SWEDISH 0
91
#define LANG_TURKISH 0
92
#define LANG_UKRAINIAN 0
94
#define LANG_VIETNAMESE 0
95
#define LANG_CHINESE 0
97
//define dummy versions of Windows sublanguage IDs
98
#define SUBLANG_DEFAULT 0
99
#define SUBLANG_BENGALI_INDIA 0
100
#define SUBLANG_BENGALI_BANGLADESH 0
101
#define SUBLANG_CHINESE_TRADITIONAL 0
102
#define SUBLANG_CHINESE_SIMPLIFIED 0
103
#define SUBLANG_DUTCH 0
104
#define SUBLANG_DUTCH_BELGIAN 0
105
#define SUBLANG_ENGLISH_UK 0
106
#define SUBLANG_ENGLISH_US 0
107
#define SUBLANG_FRENCH 0
108
#define SUBLANG_FRENCH_BELGIAN 0
109
#define SUBLANG_FRENCH_CANADIAN 0
110
#define SUBLANG_GERMAN 0
111
#define SUBLANG_GERMAN_AUSTRIAN 0
112
#define SUBLANG_GERMAN_SWISS 0
113
#define SUBLANG_LITHUANIAN 0
114
#define SUBLANG_KOREAN 0
115
#define SUBLANG_MALAY_MALAYSIA 0
116
#define SUBLANG_MALAY_BRUNEI_DARUSSALAM 0
117
#define SUBLANG_NORWEGIAN_BOKMAL 0
118
#define SUBLANG_NORWEGIAN_NYNORSK 0
119
#define SUBLANG_PORTUGUESE 0
120
#define SUBLANG_PORTUGUESE_BRAZILIAN 0
121
#define SUBLANG_SPANISH 0
122
#define SUBLANG_SWEDISH 0
123
#define SUBLANG_SERBIAN_LATIN 0
125
//some codes are not defined in Visual C++ 6.0
127
#define LANG_AMHARIC 0x5e
129
#ifndef LANG_ESPERANTO
130
#define LANG_ESPERANTO 0x8f
132
#ifndef LANG_MONGOLIAN
133
#define LANG_MONGOLIAN 0x50
135
#ifndef SUBLANG_BENGALI_INDIA
136
#define SUBLANG_BENGALI_INDIA 0x00
138
#ifndef SUBLANG_BENGALI_BANGLADESH
139
#define SUBLANG_BENGALI_BANGLADESH 0x01
145
const char *iso, *locale, *lang;
151
//TOFIX add more languages, add native language name column?
152
static LanguageStruct isoLanguages[] =
154
{"af", "af_AF", "Afrikaans", LANG_AFRIKAANS, SUBLANG_DEFAULT, false},
155
{"sq", "sq_AL", "Albanian", LANG_ALBANIAN, SUBLANG_DEFAULT, false},
156
{"am", "am_ET", "Amharic", LANG_AMHARIC, SUBLANG_DEFAULT, false},
157
{"ar", "ar", "Arabic", LANG_ARABIC, SUBLANG_DEFAULT, true},
158
{"hy", "hy", "Armenian", LANG_ARMENIAN, SUBLANG_DEFAULT, false},
159
{"eu", "eu", "Basque", LANG_BASQUE, SUBLANG_DEFAULT, false},
160
{"be", "be_BE", "Belarusian", LANG_BELARUSIAN,SUBLANG_DEFAULT, false},
161
{"bn", "bn", "Bengali", LANG_BENGALI, SUBLANG_DEFAULT, false},
162
{"bn_IN", "bn_IN", "Bengali (India)", LANG_BENGALI, SUBLANG_BENGALI_INDIA, false},
163
{"bn_BD", "bn_BD", "Bengali (Bangladesh)", LANG_BENGALI, SUBLANG_BENGALI_BANGLADESH, false},
164
{"bg", "bg_BG", "Bulgarian", LANG_BULGARIAN, SUBLANG_DEFAULT, false},
165
{"ca", "ca_ES", "Catalan", LANG_CATALAN, SUBLANG_DEFAULT, false},
166
{"zh_CN", "zh_CN", "Chinese (simplified)", LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED, false},
167
{"zh_TW", "zh_TW", "Chinese (traditional)", LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL, false},
168
{"hr", "hr_HR", "Croatian", LANG_CROATIAN, SUBLANG_DEFAULT, false},
169
{"cs", "cs_CZ", "Czech", LANG_CZECH, SUBLANG_DEFAULT, false},
170
{"da", "da_DK", "Danish", LANG_DANISH, SUBLANG_DEFAULT, false},
171
{"nl", "nl_NL", "Dutch", LANG_DUTCH, SUBLANG_DUTCH, false},
172
{"nl_BE","nl_BE", "Dutch (Belgian)", LANG_DUTCH, SUBLANG_DUTCH_BELGIAN, false},
173
{"en", "en_GB", "English", LANG_ENGLISH, SUBLANG_ENGLISH_UK, false},
174
{"en_US","en_US", "English (American)",LANG_ENGLISH, SUBLANG_ENGLISH_US, false},
175
{"et", "et_EE", "Estonian", LANG_ESTONIAN, SUBLANG_DEFAULT, false},
176
{"eo", "eo", "Esperanto", LANG_ESPERANTO, SUBLANG_DEFAULT, false},
177
{"fa", "fa_IR", "Farsi", LANG_FARSI, SUBLANG_DEFAULT, false},
178
{"fi", "fi_FI", "Finnish", LANG_FINNISH , SUBLANG_DEFAULT, false},
179
{"fr", "fr_FR", "French", LANG_FRENCH, SUBLANG_FRENCH, false},
180
{"fr_BE","fr_BE", "French (Belgian)", LANG_FRENCH, SUBLANG_FRENCH_BELGIAN, false},
181
{"fr_CA","fr_CA", "French (Canadian)", LANG_FRENCH, SUBLANG_FRENCH_CANADIAN, false},
182
{"ka", "ka", "Georgian", LANG_GEORGIAN, SUBLANG_DEFAULT, false},
183
{"de", "de_DE", "German", LANG_GERMAN, SUBLANG_GERMAN, false},
184
{"de_AT", "de_AT", "German (Austrian)", LANG_GERMAN, SUBLANG_GERMAN_AUSTRIAN, false},
185
{"de_CH", "de_CH", "German (Swiss)", LANG_GERMAN, SUBLANG_GERMAN_SWISS, false},
186
{"el", "el_GR", "Greek", LANG_GREEK, SUBLANG_DEFAULT, false},
187
{"he", "he_IL", "Hebrew", LANG_HEBREW, SUBLANG_DEFAULT, true},
188
{"hi", "hi_IN", "Hindi", LANG_HINDI, SUBLANG_DEFAULT, false},
189
{"hu", "hu_HU", "Hungarian", LANG_HUNGARIAN, SUBLANG_DEFAULT, false},
190
{"is", "is_IS", "Icelandic", LANG_ICELANDIC, SUBLANG_DEFAULT, false},
191
{"id", "id_ID", "Indonesian", LANG_INDONESIAN,SUBLANG_DEFAULT, false},
192
{"it", "it_IT", "Italian", LANG_ITALIAN, SUBLANG_DEFAULT, false},
193
{"ja", "ja_JP", "Japanese", LANG_JAPANESE, SUBLANG_DEFAULT, false},
194
{"ko", "ko_KR", "Korean", LANG_KOREAN, SUBLANG_KOREAN, false},
195
{"lv", "lv_LV", "Latvian", LANG_LATVIAN, SUBLANG_DEFAULT, false},
196
{"lt", "lt_LT", "Lithuanian", LANG_LITHUANIAN,SUBLANG_LITHUANIAN, false},
197
{"mk", "mk_MK", "Macedonian (FYROM)",LANG_MACEDONIAN,SUBLANG_DEFAULT, false},
198
{"mn", "mn", "Mongolian",LANG_MONGOLIAN,SUBLANG_DEFAULT, false},
199
{"ms", "ms_MY", "Malay (Malaysia)", LANG_MALAY, SUBLANG_MALAY_MALAYSIA, false},
200
{"ms_BN","ms_BN", "Malay (Brunei)",LANG_MALAY, SUBLANG_MALAY_BRUNEI_DARUSSALAM, false},
201
{"nb", "nb_NO", "Norwegian Bokmal", LANG_NORWEGIAN, SUBLANG_NORWEGIAN_BOKMAL, false},
202
{"nn", "nn_NO", "Norwegian Nynorsk",LANG_NORWEGIAN, SUBLANG_NORWEGIAN_NYNORSK, false},
203
{"no", "no_NO", "Norwegian", LANG_NORWEGIAN, SUBLANG_DEFAULT, false},
204
{"pl", "pl_PL", "Polish", LANG_POLISH, SUBLANG_DEFAULT, false},
205
{"pt", "pt_PT", "Portuguese", LANG_PORTUGUESE,SUBLANG_PORTUGUESE, false},
206
{"pt_BR", "pt_BR", "Portuguese (Brazilian)", LANG_PORTUGUESE,SUBLANG_PORTUGUESE_BRAZILIAN, false},
207
{"ro", "ro_RO", "Romanian", LANG_ROMANIAN, SUBLANG_DEFAULT, false},
208
{"ru", "ru_RU", "Russian", LANG_RUSSIAN, SUBLANG_DEFAULT, false},
209
//TOFIX there seems to be no cross-platform compatible locale for Serbian language
210
//"sr_CS@Latn" and "sr_CS" seem to be official codes, but do not work
212
{"sr", "sr_CS", "Serbian (Latin)", LANG_SERBIAN, SUBLANG_SERBIAN_LATIN, false},
214
//TOFIX Can not find proper locale for Fedora Core 3
215
{"sr", "sr_YU.UTF-8", "Serbian (Latin)", LANG_SERBIAN, SUBLANG_SERBIAN_LATIN, false},
217
//TOFIX {"sr_CS","sr_CS","Serbian (Cyrillic)", LANG_SERBIAN, SUBLANG_SERBIAN_CYRILLIC, false},
218
{"sk", "sk_SK", "Slovak", LANG_SLOVAK, SUBLANG_DEFAULT, false},
219
{"sl", "sl_SI", "Slovenian", LANG_SLOVENIAN, SUBLANG_DEFAULT, false},
220
{"es", "es_ES", "Spanish", LANG_SPANISH, SUBLANG_SPANISH, false},
221
{"sv", "sv_SE", "Swedish", LANG_SWEDISH, SUBLANG_SWEDISH, false},
222
{"th", "th_TH", "Thai", LANG_THAI, SUBLANG_DEFAULT, false},
223
{"bo", "bo", "Tibetan", 0, 0, false},
224
{"ta", "ta_IN", "Tamil", LANG_TAMIL, SUBLANG_DEFAULT, false},
225
{"tr", "tr_TR", "Turkish", LANG_TURKISH, SUBLANG_DEFAULT, false},
226
{"uk", "uk_UA", "Ukrainian", LANG_UKRAINIAN, SUBLANG_DEFAULT, false},
227
{"ur", "ur", "Urdu", LANG_URDU, SUBLANG_DEFAULT, false},
228
{"vi", "vi_VN", "Vietnamese", LANG_VIETNAMESE,SUBLANG_DEFAULT, false},
231
// comparator class to sort locale list by language name (ascending)
238
bool operator ()(const std::string &a, const std::string &b){
240
return (g_lang.GetLangName(a.c_str()) > g_lang.GetLangName(b.c_str()));
242
return (g_lang.GetLangName(a.c_str()) < g_lang.GetLangName(b.c_str()));
247
GuiLanguage::GuiLanguage(const char *szPackage, const char *szLocaleDir, const char *szSourceISO)
249
m_strPackage = szPackage;
250
m_strLocaleDir = szLocaleDir;
251
m_strDefaultISO = (NULL != szSourceISO)? szSourceISO : "en";
252
m_bCatalogsListed = false;
256
GuiLanguage::~GuiLanguage()
260
//maps from locale code to the language name
261
const char *GuiLanguage::GetLangName(const char *locale)
263
//match either short or long version of the locale
264
for (unsigned int i=0; i<ARRAY_COUNT(isoLanguages); i++)
265
if (0 == strcmp (isoLanguages[i].iso, locale) ||
266
0 == strcmp (isoLanguages[i].locale, locale))
267
return isoLanguages[i].lang;
269
return ""; // not found
272
const char *GuiLanguage::GetLocaleCode(const char *iso)
274
//match either short or long version of the locale
275
for (unsigned int i=0; i<ARRAY_COUNT(isoLanguages); i++)
276
if (0 == strcmp (isoLanguages[i].iso, iso))
277
return isoLanguages[i].locale;
279
return ""; // not found
282
int GuiLanguage::GetLocaleTableIdx(const char *locale)
284
//match either short or long version of the locale
285
for (unsigned int i=0; i<ARRAY_COUNT(isoLanguages); i++)
286
if (0 == strcmp (isoLanguages[i].iso, locale) ||
287
0 == strcmp (isoLanguages[i].locale, locale))
290
return -1; // not found
293
void GuiLanguage::Initialize(const char *szIsoCode)
296
//ensure some language is selected
297
if(NULL == szIsoCode || strlen(szIsoCode)==0){
298
szIsoCode = m_strDefaultISO.c_str(); //default ISO (one used in the source code)
299
//TOFIX query LANG environment variable to set default locale ?
302
// convert language ISO code to locale code
303
const char *szLocaleCode = GetLocaleCode(szIsoCode);
304
if(strlen(szLocaleCode) > 0)
306
std::string strCountry(szLocaleCode);
307
std::string::size_type nPos = strCountry.find("_");
308
if(nPos != std::string::npos)
309
strCountry = strCountry.substr(0, nPos);
311
//ensure language catalog is available
312
if( !IsLocaleAvailable(szIsoCode) &&
313
!IsLocaleAvailable(szLocaleCode) &&
314
!IsLocaleAvailable(strCountry.c_str()) )
316
szIsoCode = m_strDefaultISO.c_str(); //default ISO (one used in the source code)
317
szLocaleCode = GetLocaleCode(szIsoCode);//default locale
320
//set language localisation for this program
321
putenv( g_strconcat("LANG=", szLocaleCode, (char *)NULL) );
322
setlocale(LC_ALL, "");
324
m_nLangIdx = GetLocaleTableIdx(szIsoCode);
326
//FIX for Windows code
328
SetThreadLocale(MAKELCID(MAKELANGID(isoLanguages[m_nLangIdx].nLangID_W32, isoLanguages[m_nLangIdx].nSubLangID_W32), SORT_DEFAULT));
332
// init NLS system settings
333
bindtextdomain (m_strPackage.c_str(), m_strLocaleDir.c_str());
334
bind_textdomain_codeset (m_strPackage.c_str(), "UTF-8");
335
textdomain (m_strPackage.c_str());
337
//store locale code for later lookup
338
m_strCurLang = szIsoCode;
342
void GuiLanguage::ListAvailableCatalogs()
344
if(m_bCatalogsListed)
346
m_bCatalogsListed = true;
349
m_lstCatalogs.erase(m_lstCatalogs.begin(), m_lstCatalogs.end()); //empty the list
351
//list all subdirectories in the locale directory (subdirectory name matches the locale name)
352
std::vector<std::string> lstDirs;
353
EnumDirectory(m_strLocaleDir.c_str(), OnDirEnum, (void *)&lstDirs, ENUM_LST_DIRS);
355
//store each locale containing catalog for current package
356
for( unsigned int i=0; i<lstDirs.size(); i++)
358
//check if message catalog exists for given locale subdirectory
359
std::string strCatalog;
361
strCatalog = m_strLocaleDir;
362
strCatalog += lstDirs[i];
363
strCatalog += "\\LC_MESSAGES\\";
364
strCatalog += m_strPackage;
368
snprintf(szBuffer, sizeof(szBuffer), "%s/%s/LC_MESSAGES/%s.mo",m_strLocaleDir.c_str(), lstDirs[i].c_str(), m_strPackage.c_str());
369
strCatalog = szBuffer;
372
if(0 == access(strCatalog.c_str(), 00))
373
m_lstCatalogs.push_back(lstDirs[i]); //add locale into the list of available catalogs
376
//sort list by language names
377
std::sort(m_lstCatalogs.begin(), m_lstCatalogs.end(), CmpLang());
380
bool GuiLanguage::IsLocaleAvailable(const char *szLocale)
382
std::string strCatalog;
384
strCatalog = m_strLocaleDir;
385
strCatalog += szLocale;
386
strCatalog += "\\LC_MESSAGES\\";
387
strCatalog += m_strPackage;
391
snprintf(szBuffer, sizeof(szBuffer), "%s/%s/LC_MESSAGES/%s.mo",m_strLocaleDir.c_str(), szLocale, m_strPackage.c_str());
392
strCatalog = szBuffer;
395
return (0 == access(strCatalog.c_str(), 00));
396
//return (-1 != GetLocaleIdx(szLocale)); //old implementation (slows the program startup)
399
int GuiLanguage::GetLocaleIdx(const char *szLocale)
401
for(unsigned int i=0; i<m_lstCatalogs.size(); i++)
403
const char *szCatalogEntry = m_lstCatalogs[i].c_str();
404
if( 0 == strcmp(szCatalogEntry, szLocale) )
408
return -1; //not found
411
int GuiLanguage::GetLocaleTableIdx(int nLangID)
414
int nMax = ARRAY_COUNT(isoLanguages);
415
for (int i=0; i<nMax; i++)
416
if( nLangID == MAKELANGID(isoLanguages[i].nLangID_W32, isoLanguages[i].nSubLangID_W32))
419
return -1; //not found
422
bool OnDirEnum(const char *szDir, void *data)
424
std::vector<std::string> *lstDirs = (std::vector<std::string> *)data;
427
//calculate directory base name and add it into the list
429
//calculate base name
430
std::string strDir(szDir);
431
int nPos = strDir.find_last_of('\\');
433
strDir = strDir.substr(nPos+1, 1000);
435
std::string strDir(basename((char *)szDir));
438
lstDirs->push_back(strDir);
441
return true; //keep enumerating
444
const char *GuiLanguage::QueryLocale(int category)
446
//return current locale settings
447
//WARNING: on Windows this returns global system settings, not program's
448
return setlocale(category, NULL);
451
const char *GuiLanguage::GetLocale()
453
return m_strCurLang.c_str();
456
bool GuiLanguage::IsCurLangRTL()
459
return isoLanguages[m_nLangIdx].bRTL;
463
void GuiLanguage::InitializeToSystemLang()
466
LANGID nLangID = GetUserDefaultLangID();
467
int nIdx = GetLocaleTableIdx(nLangID);
470
Initialize(isoLanguages[nIdx].iso);
473
//query LANG environment variable to set default locale
474
const char *szLocale = getenv("LANG"); //setlocale(LC_ALL, NULL);
477
Initialize(szLocale);
1
////////////////////////////////////////////////////////////////////////////
2
// NoteCase notes manager project <http://notecase.sf.net>
4
// This code is licensed under BSD license.See "license.txt" for more details.
6
// File: Class for handling internationalisation issues (message catalogs)
7
////////////////////////////////////////////////////////////////////////////
10
#pragma warning(disable: 4996) //ignore deprecated functions warning
13
#include "../config.h"
14
#include "GuiLanguage.h"
22
#include "../lib/EnumDirectory.h"
25
#include <io.h> //access
27
#define access _access
29
#include <libgen.h> //basename on Archlinux
32
#if defined (__FreeBSD__) || defined (__APPLE__)
33
#include <libgen.h> //basename
36
extern GuiLanguage g_lang;
38
bool OnDirEnum(const char *szDir, void *data);
39
#define ARRAY_COUNT(x) (sizeof(x)/sizeof(x[0]))
42
//define dummy versions of Windows language IDs
43
#define LANG_AFRIKAANS 0
44
#define LANG_ALBANIAN 0
45
#define LANG_AMHARIC 0
47
#define LANG_ARMENIAN 0
49
#define LANG_BELARUSIAN 0
50
#define LANG_BENGALI 0
51
#define LANG_BULGARIAN 0
52
#define LANG_CATALAN 0
53
#define LANG_CROATIAN 0
57
#define LANG_ENGLISH 0
58
#define LANG_ESTONIAN 0
59
#define LANG_ESPERANTO 0
62
#define LANG_FINNISH 0
63
#define LANG_GEORGIAN 0
68
#define LANG_HUNGARIAN 0
69
#define LANG_ICELANDIC 0
70
#define LANG_INDONESIAN 0
71
#define LANG_ITALIAN 0
72
#define LANG_JAPANESE 0
74
#define LANG_LATVIAN 0
75
#define LANG_LITHUANIAN 0
76
#define LANG_MACEDONIAN 0
77
#define LANG_MONGOLIAN 0
79
#define LANG_NORWEGIAN 0
81
#define LANG_PORTUGUESE 0
82
#define LANG_ROMANIAN 0
83
#define LANG_RUSSIAN 0
84
#define LANG_SERBIAN 0
86
#define LANG_SLOVENIAN 0
87
#define LANG_SPANISH 0
88
#define LANG_SWEDISH 0
91
#define LANG_TURKISH 0
92
#define LANG_UKRAINIAN 0
94
#define LANG_VIETNAMESE 0
95
#define LANG_CHINESE 0
97
//define dummy versions of Windows sublanguage IDs
98
#define SUBLANG_DEFAULT 0
99
#define SUBLANG_BENGALI_INDIA 0
100
#define SUBLANG_BENGALI_BANGLADESH 0
101
#define SUBLANG_CHINESE_TRADITIONAL 0
102
#define SUBLANG_CHINESE_SIMPLIFIED 0
103
#define SUBLANG_DUTCH 0
104
#define SUBLANG_DUTCH_BELGIAN 0
105
#define SUBLANG_ENGLISH_UK 0
106
#define SUBLANG_ENGLISH_US 0
107
#define SUBLANG_FRENCH 0
108
#define SUBLANG_FRENCH_BELGIAN 0
109
#define SUBLANG_FRENCH_CANADIAN 0
110
#define SUBLANG_GERMAN 0
111
#define SUBLANG_GERMAN_AUSTRIAN 0
112
#define SUBLANG_GERMAN_SWISS 0
113
#define SUBLANG_LITHUANIAN 0
114
#define SUBLANG_KOREAN 0
115
#define SUBLANG_MALAY_MALAYSIA 0
116
#define SUBLANG_MALAY_BRUNEI_DARUSSALAM 0
117
#define SUBLANG_NORWEGIAN_BOKMAL 0
118
#define SUBLANG_NORWEGIAN_NYNORSK 0
119
#define SUBLANG_PORTUGUESE 0
120
#define SUBLANG_PORTUGUESE_BRAZILIAN 0
121
#define SUBLANG_SPANISH 0
122
#define SUBLANG_SWEDISH 0
123
#define SUBLANG_SERBIAN_LATIN 0
125
//some codes are not defined in Visual C++ 6.0
127
#define LANG_AMHARIC 0x5e
129
#ifndef LANG_ESPERANTO
130
#define LANG_ESPERANTO 0x8f
132
#ifndef LANG_MONGOLIAN
133
#define LANG_MONGOLIAN 0x50
135
#ifndef SUBLANG_BENGALI_INDIA
136
#define SUBLANG_BENGALI_INDIA 0x00
138
#ifndef SUBLANG_BENGALI_BANGLADESH
139
#define SUBLANG_BENGALI_BANGLADESH 0x01
145
const char *iso, *locale, *lang;
151
//TOFIX add more languages, add native language name column?
152
static LanguageStruct isoLanguages[] =
154
{"af", "af_AF", "Afrikaans", LANG_AFRIKAANS, SUBLANG_DEFAULT, false},
155
{"sq", "sq_AL", "Albanian", LANG_ALBANIAN, SUBLANG_DEFAULT, false},
156
{"am", "am_ET", "Amharic", LANG_AMHARIC, SUBLANG_DEFAULT, false},
157
{"ar", "ar", "Arabic", LANG_ARABIC, SUBLANG_DEFAULT, true},
158
{"hy", "hy", "Armenian", LANG_ARMENIAN, SUBLANG_DEFAULT, false},
159
{"eu", "eu", "Basque", LANG_BASQUE, SUBLANG_DEFAULT, false},
160
{"be", "be_BE", "Belarusian", LANG_BELARUSIAN,SUBLANG_DEFAULT, false},
161
{"bn", "bn", "Bengali", LANG_BENGALI, SUBLANG_DEFAULT, false},
162
{"bn_IN", "bn_IN", "Bengali (India)", LANG_BENGALI, SUBLANG_BENGALI_INDIA, false},
163
{"bn_BD", "bn_BD", "Bengali (Bangladesh)", LANG_BENGALI, SUBLANG_BENGALI_BANGLADESH, false},
164
{"bg", "bg_BG", "Bulgarian", LANG_BULGARIAN, SUBLANG_DEFAULT, false},
165
{"ca", "ca_ES", "Catalan", LANG_CATALAN, SUBLANG_DEFAULT, false},
166
{"zh_CN", "zh_CN", "Chinese (simplified)", LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED, false},
167
{"zh_TW", "zh_TW", "Chinese (traditional)", LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL, false},
168
{"hr", "hr_HR", "Croatian", LANG_CROATIAN, SUBLANG_DEFAULT, false},
169
{"cs", "cs_CZ", "Czech", LANG_CZECH, SUBLANG_DEFAULT, false},
170
{"da", "da_DK", "Danish", LANG_DANISH, SUBLANG_DEFAULT, false},
171
{"nl", "nl_NL", "Dutch", LANG_DUTCH, SUBLANG_DUTCH, false},
172
{"nl_BE","nl_BE", "Dutch (Belgian)", LANG_DUTCH, SUBLANG_DUTCH_BELGIAN, false},
173
{"en", "en_GB", "English", LANG_ENGLISH, SUBLANG_ENGLISH_UK, false},
174
{"en_US","en_US", "English (American)",LANG_ENGLISH, SUBLANG_ENGLISH_US, false},
175
{"et", "et_EE", "Estonian", LANG_ESTONIAN, SUBLANG_DEFAULT, false},
176
{"eo", "eo", "Esperanto", LANG_ESPERANTO, SUBLANG_DEFAULT, false},
177
{"fa", "fa_IR", "Farsi", LANG_FARSI, SUBLANG_DEFAULT, false},
178
{"fi", "fi_FI", "Finnish", LANG_FINNISH , SUBLANG_DEFAULT, false},
179
{"fr", "fr_FR", "French", LANG_FRENCH, SUBLANG_FRENCH, false},
180
{"fr_BE","fr_BE", "French (Belgian)", LANG_FRENCH, SUBLANG_FRENCH_BELGIAN, false},
181
{"fr_CA","fr_CA", "French (Canadian)", LANG_FRENCH, SUBLANG_FRENCH_CANADIAN, false},
182
{"ka", "ka", "Georgian", LANG_GEORGIAN, SUBLANG_DEFAULT, false},
183
{"de", "de_DE", "German", LANG_GERMAN, SUBLANG_GERMAN, false},
184
{"de_AT", "de_AT", "German (Austrian)", LANG_GERMAN, SUBLANG_GERMAN_AUSTRIAN, false},
185
{"de_CH", "de_CH", "German (Swiss)", LANG_GERMAN, SUBLANG_GERMAN_SWISS, false},
186
{"el", "el_GR", "Greek", LANG_GREEK, SUBLANG_DEFAULT, false},
187
{"he", "he_IL", "Hebrew", LANG_HEBREW, SUBLANG_DEFAULT, true},
188
{"hi", "hi_IN", "Hindi", LANG_HINDI, SUBLANG_DEFAULT, false},
189
{"hu", "hu_HU", "Hungarian", LANG_HUNGARIAN, SUBLANG_DEFAULT, false},
190
{"is", "is_IS", "Icelandic", LANG_ICELANDIC, SUBLANG_DEFAULT, false},
191
{"id", "id_ID", "Indonesian", LANG_INDONESIAN,SUBLANG_DEFAULT, false},
192
{"it", "it_IT", "Italian", LANG_ITALIAN, SUBLANG_DEFAULT, false},
193
{"ja", "ja_JP", "Japanese", LANG_JAPANESE, SUBLANG_DEFAULT, false},
194
{"ko", "ko_KR", "Korean", LANG_KOREAN, SUBLANG_KOREAN, false},
195
{"lv", "lv_LV", "Latvian", LANG_LATVIAN, SUBLANG_DEFAULT, false},
196
{"lt", "lt_LT", "Lithuanian", LANG_LITHUANIAN,SUBLANG_LITHUANIAN, false},
197
{"mk", "mk_MK", "Macedonian (FYROM)",LANG_MACEDONIAN,SUBLANG_DEFAULT, false},
198
{"mn", "mn", "Mongolian",LANG_MONGOLIAN,SUBLANG_DEFAULT, false},
199
{"ms", "ms_MY", "Malay (Malaysia)", LANG_MALAY, SUBLANG_MALAY_MALAYSIA, false},
200
{"ms_BN","ms_BN", "Malay (Brunei)",LANG_MALAY, SUBLANG_MALAY_BRUNEI_DARUSSALAM, false},
201
{"nb", "nb_NO", "Norwegian Bokmal", LANG_NORWEGIAN, SUBLANG_NORWEGIAN_BOKMAL, false},
202
{"nn", "nn_NO", "Norwegian Nynorsk",LANG_NORWEGIAN, SUBLANG_NORWEGIAN_NYNORSK, false},
203
{"no", "no_NO", "Norwegian", LANG_NORWEGIAN, SUBLANG_DEFAULT, false},
204
{"pl", "pl_PL", "Polish", LANG_POLISH, SUBLANG_DEFAULT, false},
205
{"pt", "pt_PT", "Portuguese", LANG_PORTUGUESE,SUBLANG_PORTUGUESE, false},
206
{"pt_BR", "pt_BR", "Portuguese (Brazilian)", LANG_PORTUGUESE,SUBLANG_PORTUGUESE_BRAZILIAN, false},
207
{"ro", "ro_RO", "Romanian", LANG_ROMANIAN, SUBLANG_DEFAULT, false},
208
{"ru", "ru_RU", "Russian", LANG_RUSSIAN, SUBLANG_DEFAULT, false},
209
//TOFIX there seems to be no cross-platform compatible locale for Serbian language
210
//"sr_CS@Latn" and "sr_CS" seem to be official codes, but do not work
212
{"sr", "sr_CS", "Serbian (Latin)", LANG_SERBIAN, SUBLANG_SERBIAN_LATIN, false},
214
//TOFIX Can not find proper locale for Fedora Core 3
215
{"sr", "sr_YU.UTF-8", "Serbian (Latin)", LANG_SERBIAN, SUBLANG_SERBIAN_LATIN, false},
217
//TOFIX {"sr_CS","sr_CS","Serbian (Cyrillic)", LANG_SERBIAN, SUBLANG_SERBIAN_CYRILLIC, false},
218
{"sk", "sk_SK", "Slovak", LANG_SLOVAK, SUBLANG_DEFAULT, false},
219
{"sl", "sl_SI", "Slovenian", LANG_SLOVENIAN, SUBLANG_DEFAULT, false},
220
{"es", "es_ES", "Spanish", LANG_SPANISH, SUBLANG_SPANISH, false},
221
{"sv", "sv_SE", "Swedish", LANG_SWEDISH, SUBLANG_SWEDISH, false},
222
{"th", "th_TH", "Thai", LANG_THAI, SUBLANG_DEFAULT, false},
223
{"bo", "bo", "Tibetan", 0, 0, false},
224
{"ta", "ta_IN", "Tamil", LANG_TAMIL, SUBLANG_DEFAULT, false},
225
{"tr", "tr_TR", "Turkish", LANG_TURKISH, SUBLANG_DEFAULT, false},
226
{"uk", "uk_UA", "Ukrainian", LANG_UKRAINIAN, SUBLANG_DEFAULT, false},
227
{"ur", "ur", "Urdu", LANG_URDU, SUBLANG_DEFAULT, false},
228
{"vi", "vi_VN", "Vietnamese", LANG_VIETNAMESE,SUBLANG_DEFAULT, false},
231
// comparator class to sort locale list by language name (ascending)
238
bool operator ()(const std::string &a, const std::string &b){
240
return (g_lang.GetLangName(a.c_str()) > g_lang.GetLangName(b.c_str()));
242
return (g_lang.GetLangName(a.c_str()) < g_lang.GetLangName(b.c_str()));
247
GuiLanguage::GuiLanguage(const char *szPackage, const char *szLocaleDir, const char *szSourceISO)
249
m_strPackage = szPackage;
250
m_strLocaleDir = szLocaleDir;
251
m_strDefaultISO = (NULL != szSourceISO)? szSourceISO : "en";
252
m_bCatalogsListed = false;
256
GuiLanguage::~GuiLanguage()
260
//maps from locale code to the language name
261
const char *GuiLanguage::GetLangName(const char *locale)
263
//match either short or long version of the locale
264
for (unsigned int i=0; i<ARRAY_COUNT(isoLanguages); i++)
265
if (0 == strcmp (isoLanguages[i].iso, locale) ||
266
0 == strcmp (isoLanguages[i].locale, locale))
267
return isoLanguages[i].lang;
269
return ""; // not found
272
const char *GuiLanguage::GetLocaleCode(const char *iso)
274
//match either short or long version of the locale
275
for (unsigned int i=0; i<ARRAY_COUNT(isoLanguages); i++)
276
if (0 == strcmp (isoLanguages[i].iso, iso))
277
return isoLanguages[i].locale;
279
return ""; // not found
282
int GuiLanguage::GetLocaleTableIdx(const char *locale)
284
//match either short or long version of the locale
285
for (unsigned int i=0; i<ARRAY_COUNT(isoLanguages); i++)
286
if (0 == strcmp (isoLanguages[i].iso, locale) ||
287
0 == strcmp (isoLanguages[i].locale, locale))
290
return -1; // not found
293
void GuiLanguage::Initialize(const char *szIsoCode)
296
//ensure some language is selected
297
if(NULL == szIsoCode || strlen(szIsoCode)==0){
298
szIsoCode = m_strDefaultISO.c_str(); //default ISO (one used in the source code)
299
//TOFIX query LANG environment variable to set default locale ?
302
// convert language ISO code to locale code
303
const char *szLocaleCode = GetLocaleCode(szIsoCode);
304
if(strlen(szLocaleCode) > 0)
306
std::string strCountry(szLocaleCode);
307
std::string::size_type nPos = strCountry.find("_");
308
if(nPos != std::string::npos)
309
strCountry = strCountry.substr(0, nPos);
311
//ensure language catalog is available
312
if( !IsLocaleAvailable(szIsoCode) &&
313
!IsLocaleAvailable(szLocaleCode) &&
314
!IsLocaleAvailable(strCountry.c_str()) )
316
szIsoCode = m_strDefaultISO.c_str(); //default ISO (one used in the source code)
317
szLocaleCode = GetLocaleCode(szIsoCode);//default locale
320
//set language localisation for this program
321
putenv( g_strconcat("LANG=", szLocaleCode, (char *)NULL) );
322
setlocale(LC_ALL, "");
324
m_nLangIdx = GetLocaleTableIdx(szIsoCode);
326
//FIX for Windows code
328
SetThreadLocale(MAKELCID(MAKELANGID(isoLanguages[m_nLangIdx].nLangID_W32, isoLanguages[m_nLangIdx].nSubLangID_W32), SORT_DEFAULT));
332
// init NLS system settings
333
bindtextdomain (m_strPackage.c_str(), m_strLocaleDir.c_str());
334
bind_textdomain_codeset (m_strPackage.c_str(), "UTF-8");
335
textdomain (m_strPackage.c_str());
337
//store locale code for later lookup
338
m_strCurLang = szIsoCode;
342
void GuiLanguage::ListAvailableCatalogs()
344
if(m_bCatalogsListed)
346
m_bCatalogsListed = true;
349
m_lstCatalogs.erase(m_lstCatalogs.begin(), m_lstCatalogs.end()); //empty the list
351
//list all subdirectories in the locale directory (subdirectory name matches the locale name)
352
std::vector<std::string> lstDirs;
353
EnumDirectory(m_strLocaleDir.c_str(), OnDirEnum, (void *)&lstDirs, ENUM_LST_DIRS);
355
//store each locale containing catalog for current package
356
for( unsigned int i=0; i<lstDirs.size(); i++)
358
//check if message catalog exists for given locale subdirectory
359
std::string strCatalog;
361
strCatalog = m_strLocaleDir;
362
strCatalog += lstDirs[i];
363
strCatalog += "\\LC_MESSAGES\\";
364
strCatalog += m_strPackage;
368
snprintf(szBuffer, sizeof(szBuffer), "%s/%s/LC_MESSAGES/%s.mo",m_strLocaleDir.c_str(), lstDirs[i].c_str(), m_strPackage.c_str());
369
strCatalog = szBuffer;
372
if(0 == access(strCatalog.c_str(), 00))
373
m_lstCatalogs.push_back(lstDirs[i]); //add locale into the list of available catalogs
376
//sort list by language names
377
std::sort(m_lstCatalogs.begin(), m_lstCatalogs.end(), CmpLang());
380
bool GuiLanguage::IsLocaleAvailable(const char *szLocale)
382
std::string strCatalog;
384
strCatalog = m_strLocaleDir;
385
strCatalog += szLocale;
386
strCatalog += "\\LC_MESSAGES\\";
387
strCatalog += m_strPackage;
391
snprintf(szBuffer, sizeof(szBuffer), "%s/%s/LC_MESSAGES/%s.mo",m_strLocaleDir.c_str(), szLocale, m_strPackage.c_str());
392
strCatalog = szBuffer;
395
return (0 == access(strCatalog.c_str(), 00));
396
//return (-1 != GetLocaleIdx(szLocale)); //old implementation (slows the program startup)
399
int GuiLanguage::GetLocaleIdx(const char *szLocale)
401
for(unsigned int i=0; i<m_lstCatalogs.size(); i++)
403
const char *szCatalogEntry = m_lstCatalogs[i].c_str();
404
if( 0 == strcmp(szCatalogEntry, szLocale) )
408
return -1; //not found
411
int GuiLanguage::GetLocaleTableIdx(int nLangID)
414
int nMax = ARRAY_COUNT(isoLanguages);
415
for (int i=0; i<nMax; i++)
416
if( nLangID == MAKELANGID(isoLanguages[i].nLangID_W32, isoLanguages[i].nSubLangID_W32))
419
return -1; //not found
422
bool OnDirEnum(const char *szDir, void *data)
424
std::vector<std::string> *lstDirs = (std::vector<std::string> *)data;
427
//calculate directory base name and add it into the list
429
//calculate base name
430
std::string strDir(szDir);
431
int nPos = strDir.find_last_of('\\');
433
strDir = strDir.substr(nPos+1, 1000);
435
std::string strDir(basename((char *)szDir));
438
lstDirs->push_back(strDir);
441
return true; //keep enumerating
444
const char *GuiLanguage::QueryLocale(int category)
446
//return current locale settings
447
//WARNING: on Windows this returns global system settings, not program's
448
return setlocale(category, NULL);
451
const char *GuiLanguage::GetLocale()
453
return m_strCurLang.c_str();
456
bool GuiLanguage::IsCurLangRTL()
459
return isoLanguages[m_nLangIdx].bRTL;
463
void GuiLanguage::InitializeToSystemLang()
466
LANGID nLangID = GetUserDefaultLangID();
467
int nIdx = GetLocaleTableIdx(nLangID);
470
Initialize(isoLanguages[nIdx].iso);
473
//query LANG environment variable to set default locale
474
const char *szLocale = getenv("LANG"); //setlocale(LC_ALL, NULL);
477
Initialize(szLocale);