94d24dee15e1d24e3fc5e9a080efda4ae2093b71
[scilab.git] / scilab / modules / localization / src / c / setgetlanguage.c
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2007-2008 - INRIA - Sylvestre LEDRU
4  * Copyright (C) 2007-2008 - INRIA - Allan CORNET
5  * Copyright (C) 2008 - Yung-Jang Lee
6  * Copyright (C) 2011 - 2011 - DIGITEO - Bruno JOFRET
7  *
8  * This file must be used under the terms of the CeCILL.
9  * This source file is licensed as described in the file COPYING, which
10  * you should have received as part of this distribution.  The terms
11  * are also available at
12  * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
13  *
14  */
15
16 #include <wchar.h>
17 #include <string.h>
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include "machine.h" /*  HAVE_LIBINTL_H &  HAVE_LOCALE_H */
21
22 #ifndef _MSC_VER
23 #ifdef __APPLE__
24 #include <locale.h>
25 #else
26 #ifdef HAVE_LIBINTL_H
27 #include <libintl.h>
28 #ifdef HAVE_LOCALE_H
29 #include <locale.h>
30 #else
31 #error "Cannot find locale.h despite that libintl.h is available"
32 #endif
33 #endif
34 #endif
35 #else
36 #include <locale.h>
37 #include <libintl.h>
38 #endif
39
40 #ifdef _MSC_VER
41 #include <windows.h>
42 #include "getLocaleInfo_Windows.h"
43 #endif
44 #ifdef __APPLE__
45 #include "getLocaleInfo_Apple.h"
46 #endif
47
48
49 #include "setgetlanguage.h"
50 #include "sci_malloc.h"
51 #include "tableslanguages.h"
52 #include "defaultlanguage.h"
53 #include "scilabDefaults.h"
54 #include "charEncoding.h"
55 #include "../../../io/includes/setenvc.h"
56 #include "os_string.h"
57
58 /*--------------------------------------------------------------------------*/
59 //static wchar_t CURRENTLANGUAGESTRING[LengthAlphacode] = SCILABDEFAULTLANGUAGE;
60 static wchar_t CURRENTLANGUAGESTRING[LengthAlphacode] = L"en_US";
61 static int  CURRENTLANGUAGECODE = SCILABDEFAULTLANGUAGECODE;
62 /*--------------------------------------------------------------------------*/
63 static int FindLanguageCode(const wchar_t *lang);
64 static BOOL setlanguagecode(const wchar_t *lang);
65 static const wchar_t *FindAlias(const wchar_t *lang);
66 static const wchar_t *GetLanguageFromAlias(const wchar_t *langAlias);
67 /*--------------------------------------------------------------------------*/
68 BOOL setlanguage(const wchar_t *lang)
69 {
70     if (lang)
71     {
72         if (LanguageIsOK(lang))
73         {
74 #ifndef _MSC_VER
75             if (needtochangelanguage(lang))
76             {
77 #endif
78                 /* Load the locale from the system */
79 #if !defined(_MSC_VER)
80                 //for mbstowcs
81
82                 char *newlang = NULL;
83                 char *pstLang = wide_string_to_UTF8(lang);
84                 char *pstRet = setlocale(LC_CTYPE, pstLang);
85                 wchar_t *ret = NULL;
86
87 #ifdef __APPLE__
88                 /* Load the user locale from the system */
89                 if (pstLang == NULL || *pstLang == 0)
90                 {
91                     if (pstLang)
92                     {
93                         FREE(pstLang);
94                     }
95                     pstLang = wide_string_to_UTF8(getLocaleUserInfo());
96                 }
97 #endif
98
99                 if (pstRet == NULL)
100                 {
101                     if (pstLang == NULL || *pstLang == 0)
102                     {
103                         if (pstLang)
104                         {
105                             FREE(pstLang);
106                         }
107
108                         pstLang = strdup(getenv("LANG"));
109                     }
110
111                     pstRet = setlocale(LC_CTYPE, pstLang);
112                     if (pstRet == NULL)
113                     {
114                         // On some OSes we need to precise the charset (e.g. on Debian, fr_FR is not accepted but fr_FR.UTF-8 is)
115                         int i = 0;
116                         for (; i < NumberOfCharsets; i++)
117                         {
118                             newlang = (char*)MALLOC(strlen(pstLang) + strlen(CHARSETS[i]) + 1 + 1);
119                             sprintf(newlang, "%s.%s", pstLang, CHARSETS[i]);
120                             pstRet = setlocale(LC_CTYPE, newlang);
121                             if (pstRet == NULL)
122                             {
123                                 FREE(newlang);
124                                 newlang = NULL;
125                             }
126                             else
127                             {
128                                 break;
129                             }
130                         }
131                     }
132                 }
133
134                 if (pstRet == NULL)
135                 {
136                     fprintf(stderr,
137                             "Warning: Localization issue. Failed to change the LC_CTYPE locale category. Does not support the locale '%ls' %ls %s.\nDid you install the system locales?\n",
138                             lang, ret, setlocale(LC_CTYPE, NULL));
139                 }
140
141                 //for gettext
142                 if (newlang)
143                 {
144                     pstRet = setlocale(LC_MESSAGES, newlang);
145                 }
146                 else
147                 {
148                     pstRet = setlocale(LC_MESSAGES, pstLang);
149                 }
150
151                 ret = to_wide_string(pstRet);
152 #else
153                 /* Load the user locale from the system */
154                 wchar_t *ret = getLocaleUserInfo();
155
156
157 #endif
158
159                 // This stuff causes pb when locales have been compiled
160                 if (ret == NULL)
161                 {
162 #ifndef _MSC_VER
163                     fprintf(stderr, "Warning: Localization issue. Does not support the locale '%ls'\nReturned: NULL\nCurrent system locale: %s\nDid you install the system locales?\n", lang,
164                             setlocale(LC_MESSAGES, NULL));
165 #else
166                     fprintf(stderr, "Warning: Localization issue. Cannot detect user locale.\n");
167 #endif
168                 }
169
170                 /* change language */
171                 if (wcscmp(lang, L"C") == 0 || ret == NULL || wcscmp(ret, L"C") == 0)
172                 {
173                     /* The lang is the default one... ie en_US */
174                     wcscpy(CURRENTLANGUAGESTRING, SCILABDEFAULTLANGUAGE);
175                     exportLocaleToSystem(CURRENTLANGUAGESTRING);
176                 }
177                 else
178                 {
179                     if (wcscmp(lang, L"") == 0)
180                     {
181                         /* The requested language is the one of the system ...
182                          * which we don't really know which one is it
183                          * but if setlocale worked, we get it from the return
184                          */
185                         wcsncpy(CURRENTLANGUAGESTRING, ret, 5); /* 5 is the number of char in fr_FR for example */
186                         exportLocaleToSystem(ret);
187                     }
188                     else
189                     {
190 #if !defined(_MSC_VER)
191                         if (newlang)
192                         {
193                             wchar_t* pwstLang = to_wide_string(newlang);
194                             setenvc("LANG", newlang);
195                             wcsncpy(CURRENTLANGUAGESTRING, pwstLang, 5);
196                             CURRENTLANGUAGESTRING[5] = '\0';
197                             exportLocaleToSystem(pwstLang);
198                             FREE(pwstLang);
199                         }
200                         else
201 #endif
202                         {
203                             wcscpy(CURRENTLANGUAGESTRING, lang);
204                             exportLocaleToSystem(lang);
205                         }
206                     }
207                 }
208 #ifndef _MSC_VER
209                 setlanguagecode(CURRENTLANGUAGESTRING);
210 #ifndef __APPLE__
211                 if (newlang)
212                 {
213                     FREE(newlang);
214                 }
215 #endif
216                 FREE(pstLang);
217 #endif
218                 FREE(ret);
219                 return TRUE;
220             }
221 #ifndef _MSC_VER
222         }
223 #endif
224     }
225     return FALSE;
226 }
227 /*--------------------------------------------------------------------------*/
228 const wchar_t *getlanguage(void)
229 {
230     return CURRENTLANGUAGESTRING;
231 }
232 /*--------------------------------------------------------------------------*/
233 int getcurrentlanguagecode(void)
234 {
235     return CURRENTLANGUAGECODE;
236 }
237 /*--------------------------------------------------------------------------*/
238 const wchar_t *getlanguagefromcode(int code)
239 {
240     int i = 0;
241
242     for (i = 0 ; i < NumberLanguages ; i++)
243     {
244         if (LANGUAGE_COUNTRY_TAB[i].code == code)
245         {
246             return LANGUAGE_COUNTRY_TAB[i].alphacode;
247         }
248     }
249     return NULL;
250 }
251 /*--------------------------------------------------------------------------*/
252 int getcodefromlanguage(const wchar_t *language)
253 {
254     return FindLanguageCode(language);
255 }
256 /*--------------------------------------------------------------------------*/
257 BOOL LanguageIsOK(const wchar_t *lang)
258 {
259     int i = 0;
260
261     if (wcslen(lang) == 0)
262     {
263         /* Empty language declaration... it is the default
264         * language from the system */
265         return TRUE;
266     }
267
268     for (i = 0 ; i < NumberLanguages ; i++)
269     {
270         if (wcscmp(lang, LANGUAGE_COUNTRY_TAB[i].alphacode) == 0)
271         {
272             return TRUE;
273         }
274     }
275     return FALSE;
276 }
277 /*--------------------------------------------------------------------------*/
278 static int FindLanguageCode(const wchar_t *lang)
279 {
280     int i = 0;
281
282     for (i = 0 ; i < NumberLanguages ; i++)
283     {
284         if (wcscmp(lang, LANGUAGE_COUNTRY_TAB[i].alphacode) == 0)
285         {
286             return LANGUAGE_COUNTRY_TAB[i].code;
287         }
288     }
289     return -1;
290 }
291 /*--------------------------------------------------------------------------*/
292 static BOOL setlanguagecode(const wchar_t *lang)
293 {
294     int tmpCode = FindLanguageCode(lang);
295
296     if (tmpCode > 0)
297     {
298         CURRENTLANGUAGECODE = tmpCode;
299         return TRUE;
300     }
301     return FALSE;
302 }
303 /*--------------------------------------------------------------------------*/
304 static const wchar_t *FindAlias(const wchar_t *lang)
305 {
306     int i = 0;
307     for (i = 0 ; i < NumberLanguagesAlias ; i++)
308     {
309         if (wcscmp(LANGUAGE_LOCALE_ALIAS[i].alphacode, lang) == 0)
310         {
311             return LANGUAGE_LOCALE_ALIAS[i].alias;
312         }
313     }
314     return NULL;
315 }
316 /*--------------------------------------------------------------------------*/
317 static const wchar_t *GetLanguageFromAlias(const wchar_t *langAlias)
318 {
319     int i = 0;
320     for (i = 0 ; i < NumberLanguagesAlias ; i++)
321     {
322         if (wcscmp(LANGUAGE_LOCALE_ALIAS[i].alias, langAlias) == 0)
323         {
324             return LANGUAGE_LOCALE_ALIAS[i].alphacode;
325         }
326     }
327     return NULL;
328 }
329 /*--------------------------------------------------------------------------*/
330 const wchar_t *getlanguagealias(void)
331 {
332     return FindAlias(CURRENTLANGUAGESTRING);
333 }
334 /*--------------------------------------------------------------------------*/
335 BOOL needtochangelanguage(const wchar_t *language)
336 {
337     const wchar_t *currentlanguage = getlanguage();
338
339     if (wcscmp(language, currentlanguage))
340     {
341         return TRUE;
342     }
343
344     return FALSE;
345 }
346 /*--------------------------------------------------------------------------*/
347 const wchar_t *convertlanguagealias(const wchar_t *strlanguage)
348 {
349     const wchar_t *correctlanguage = NULL;
350
351     if ( (wcslen(strlanguage) == 2) || (wcscmp(strlanguage, L"en_US") == 0) ) /* If the user wants to change to en_US ... use the default locale */
352     {
353         correctlanguage = GetLanguageFromAlias(strlanguage);
354     }
355     else
356     {
357         if (wcscmp(strlanguage, L"eng") == 0) /* compatibility previous scilab */
358         {
359             correctlanguage = GetLanguageFromAlias(L"en");
360         }
361         else
362         {
363             if (wcslen(strlanguage) == 5 && strlanguage[2] == L'_')
364             {
365                 /* already xx_XX (fr_FR) */
366                 return strlanguage;
367             }
368         }
369     }
370     return correctlanguage;
371 }
372 /*--------------------------------------------------------------------------*/
373 /**
374  * Export the variable LC_XXXX to the system
375  *
376  * @param locale the locale (ex : fr_FR or en_US)
377  */
378 BOOL exportLocaleToSystem(const wchar_t *locale)
379 {
380
381     if (locale == NULL)
382     {
383 #ifdef _MSC_VER
384         fprintf(stderr, "Localization: Have not been able to find a suitable locale. Remains to default %s.\n", "LC_CTYPE");
385 #else
386         fprintf(stderr, "Localization: Have not been able to find a suitable locale. Remains to default %ls.\n", EXPORTENVLOCALESTR);
387 #endif
388         return FALSE;
389     }
390
391     /* It will put in the env something like LC_MESSAGES=fr_FR */
392     if ( !setenvcW(EXPORTENVLOCALESTR, locale))
393     {
394 #ifdef _MSC_VER
395         fprintf(stderr, "Localization: Failed to declare the system variable %s.\n", "LC_CTYPE");
396 #else
397         fprintf(stderr, "Localization: Failed to declare the system variable %d.\n", EXPORTENVLOCALE);
398 #endif
399         return FALSE;
400     }
401
402 #ifdef _MSC_VER
403 #ifdef USE_SAFE_GETTEXT_DLL
404     {
405         /* gettext is buggy on Windows */
406         /* We need to set a external environment variable to scilab env. */
407         char* pstr = NULL;
408         wchar_t env[MAX_PATH];
409         os_swprintf(env, MAX_PATH, L"%ls=%ls", EXPORTENVLOCALESTR, locale);
410         pstr = wide_string_to_UTF8(env);
411         gettext_putenv(pstr);
412         FREE(pstr);
413     }
414 #endif
415 #else
416     /* Export LC_NUMERIC to the system to make sure that the rest of system
417        is using the english notation (Java, Tcl ...) */
418     setenvc("LC_NUMERIC", LCNUMERICVALUE);
419 #endif
420
421     return TRUE;
422 }
423 /*--------------------------------------------------------------------------*/