9f4cf72d1207a72b7c06a67df9ac9261195bdc32
[blender.git] / source / blender / blenfont / intern / blf_lang.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2008 Blender Foundation.
19  * All rights reserved.
20  * 
21  * Contributor(s): Blender Foundation.
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/blenfont/intern/blf_lang.c
27  *  \ingroup blf
28  */
29
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 #include "BKE_global.h"
36
37 #include "BLF_api.h"
38 #include "BLF_translation.h" /* own include */
39
40 #ifdef WITH_INTERNATIONAL
41
42 #include <locale.h>
43
44 #include "libintl.h"
45
46 #include "DNA_userdef_types.h"
47
48 #include "RNA_types.h"
49
50 #include "MEM_guardedalloc.h"
51
52 #include "BLI_string.h"
53 #include "BLI_utildefines.h"
54 #include "BLI_path_util.h"
55 #include "BLI_fileops.h"
56 #include "BLI_linklist.h"
57 #include "BLI_string.h"
58
59 #define SYSTEM_ENCODING_DEFAULT "UTF-8"
60 #define FONT_SIZE_DEFAULT 12
61
62 /* Locale options. */
63 static char global_messagepath[1024];
64 static char global_language[32];
65 static char global_encoding_name[32];
66
67 static const char **locales = NULL;
68 static int num_locales = 0;
69 static EnumPropertyItem *locales_menu = NULL;
70 static int num_locales_menu = 0;
71
72 #define ULANGUAGE ((U.language >= 0 && U.language < num_locales) ? U.language : 0)
73 #define LOCALE(_id) (locales ? locales[_id] : "")
74
75 static void free_locales(void)
76 {
77         if (locales) {
78                 int idx = num_locales_menu - 1; /* Last item does not need to be freed! */
79                 while (idx--) {
80                         MEM_freeN((void*)locales_menu[idx].identifier);
81                         MEM_freeN((void*)locales_menu[idx].name);
82                         MEM_freeN((void*)locales_menu[idx].description); /* Also frees locales's relevant value! */
83                 }
84                 MEM_freeN(locales);
85                 locales = NULL;
86         }
87         if (locales_menu) {
88                 MEM_freeN(locales_menu);
89                 locales_menu = NULL;
90         }
91         num_locales = num_locales_menu = 0;
92 }
93
94 static void fill_locales(void)
95 {
96         char *languages_path = BLI_get_folder(BLENDER_DATAFILES, "locale");
97         LinkNode *lines = NULL, *line;
98         char *str;
99         int idx = 0;
100
101         free_locales();
102
103         BLI_join_dirfile(languages_path, FILE_MAX, languages_path, "languages");
104         line = lines = BLI_file_read_as_lines(languages_path);
105
106         /* This whole "parsing" code is a bit weak, in that it expects strictly formated input file...
107          * Should not be a problem, though, as this file is script-generated! */
108
109         /* First loop to find highest locale ID */
110         while (line) {
111                 int t;
112                 str = (char*) line->link;
113                 if (str[0] == '#' || str[0] == '\0') {
114                         line = line->next;
115                         continue; /* Comment or void... */
116                 }
117                 t = atoi(str);
118                 if (t >= num_locales)
119                         num_locales = t + 1;
120                 num_locales_menu++;
121                 line = line->next;
122         }
123         num_locales_menu++; /* The "closing" void item... */
124
125         /* And now, buil locales and locale_menu! */
126         locales_menu = MEM_callocN(num_locales_menu * sizeof(EnumPropertyItem), __func__);
127         line = lines;
128         /* Do not allocate locales with zero-sized mem, as LOCALE macro uses NULL locales as invalid marker! */
129         if (num_locales > 0) {
130                 locales = MEM_callocN(num_locales * sizeof(char*), __func__);
131                 while (line) {
132                         int id;
133                         char *loc, *sep1, *sep2;
134
135                         str = (char*) line->link;
136                         if (str[0] == '#' || str[0] == '\0') {
137                                 line = line->next;
138                                 continue;
139                         }
140
141                         id = atoi(str);
142                         sep1 = strchr(str, ':');
143                         if (sep1) {
144                                 sep1++;
145                                 sep2 = strchr(sep1, ':');
146                                 if (sep2) {
147
148                                                 locales_menu[idx].value = id;
149                                                 locales_menu[idx].icon = 0;
150                                                 locales_menu[idx].name = BLI_strdupn(sep1, sep2 - sep1);
151                                                 locales_menu[idx].identifier = loc = BLI_strdup(sep2 + 1);
152                                                 if (id == 0) {
153                                                         /* The DEFAULT item... */
154                                                         if (BLI_strnlen(loc, 2))
155                                                                 locales[id] = locales_menu[idx].description = BLI_strdup("");
156                                                         /* Menu "label", not to be stored in locales! */
157                                                         else
158                                                                 locales_menu[idx].description = BLI_strdup("");
159                                                 }
160                                                 else
161                                                         locales[id] = locales_menu[idx].description = BLI_strdup(loc);
162                                                 idx++;
163                                 
164                                 }
165                         }
166
167                         line = line->next;
168                 }
169         }
170
171         /* Add closing item to menu! */
172         locales_menu[idx].identifier = NULL;
173         locales_menu[idx].value = locales_menu[idx].icon = 0;
174         locales_menu[idx].name = locales_menu[idx].description = "";
175
176         BLI_file_free_lines(lines);
177 }
178
179 EnumPropertyItem *BLF_RNA_lang_enum_properties(void)
180 {
181         return locales_menu;
182 }
183
184 void BLF_lang_init(void)
185 {
186         char *messagepath = BLI_get_folder(BLENDER_DATAFILES, "locale");
187
188         BLI_strncpy(global_encoding_name, SYSTEM_ENCODING_DEFAULT, sizeof(global_encoding_name));
189
190         if (messagepath) {
191                 BLI_strncpy(global_messagepath, messagepath, sizeof(global_messagepath));
192                 fill_locales();
193         }
194         else {
195                 printf("%s: 'locale' data path for translations not found, continuing\n", __func__);
196                 global_messagepath[0] = '\0';
197         }
198 }
199
200 void BLF_lang_free(void)
201 {
202         free_locales();
203 }
204
205 /* Get LANG/LANGUAGE environment variable. */
206 static void get_language_variable(const char *varname, char *var, const size_t maxlen)
207 {
208         char *env = getenv(varname);
209
210         if (env) {
211                 char *s;
212
213                 /* Store defaul locale. */
214                 BLI_strncpy(var, env, maxlen);
215
216                 /* Use first language as default. */
217                 s = strchr(var, ':');
218                 if (s)
219                         s[0] = 0;
220         }
221 }
222
223 /* Get language to be used based on locale (which might be empty when using default language) and
224  * LANG environment variable.
225  */
226 static void get_language(const char *locale, const char *lang, char *language, const size_t maxlen)
227 {
228         if (locale[0]) {
229                 BLI_strncpy(language, locale, maxlen);
230         }
231         else {
232                 char *s;
233
234                 BLI_strncpy(language, lang, maxlen);
235
236                 s = strchr(language, '.');
237                 if (s)
238                         s[0] = 0;
239         }
240 }
241
242 /* XXX WARNING!!! In osx somehow the previous function call jumps in this one??? (ton, ppc) */
243 void BLF_lang_set(const char *str)
244 {
245         char *locreturn;
246         const char *short_locale;
247         int ok = TRUE;
248         int ulang = ULANGUAGE;
249
250         if ((U.transopts & USER_DOTRANSLATE) == 0)
251                 return;
252
253         if (str)
254                 short_locale = str;
255         else
256                 short_locale = LOCALE(ulang);
257
258 #if defined(_WIN32) && !defined(FREE_WINDOWS)
259         {
260                 if (short_locale) {
261                         char *envStr;
262
263                         if (ulang) /* Use system setting. */
264                                 envStr = BLI_sprintfN("LANG=%s", getenv("LANG"));
265                         else
266                                 envStr = BLI_sprintfN("LANG=%s", short_locale);
267
268                         gettext_putenv(envStr);
269                         MEM_freeN(envStr);
270                 }
271
272                 locreturn = setlocale(LC_ALL, short_locale);
273
274                 if (locreturn == NULL) {
275                         if (G.debug & G_DEBUG)
276                                 printf("Could not change locale to %s\n", short_locale);
277
278                         ok = FALSE;
279                 }
280         }
281 #else
282         {
283                 static char default_lang[64] = "\0";
284                 static char default_language[64] = "\0";
285
286                 if (default_lang[0] == 0)
287                         get_language_variable("LANG", default_lang, sizeof(default_lang));
288
289                 if (default_language[0] == 0)
290                         get_language_variable("LANGUAGE", default_language, sizeof(default_language));
291
292                 if (short_locale[0]) {
293                         char *short_locale_utf8 = BLI_sprintfN("%s.UTF-8", short_locale);
294
295                         if (G.debug & G_DEBUG)
296                                 printf("Setting LANG and LANGUAGE to %s\n", short_locale_utf8);
297
298                         locreturn = setlocale(LC_ALL, short_locale_utf8);
299
300                         if (locreturn != NULL) {
301                                 BLI_setenv("LANG", short_locale_utf8);
302                                 BLI_setenv("LANGUAGE", short_locale_utf8);
303                         }
304                         else {
305                                 if (G.debug & G_DEBUG)
306                                         printf("Setting LANG and LANGUAGE to %s\n", short_locale);
307
308                                 locreturn = setlocale(LC_ALL, short_locale);
309
310                                 if (locreturn != NULL) {
311                                         BLI_setenv("LANG", short_locale);
312                                         BLI_setenv("LANGUAGE", short_locale);
313                                 }
314                         }
315
316                         if (G.debug & G_DEBUG && locreturn == NULL)
317                                 printf("Could not change locale to %s nor %s\n", short_locale, short_locale_utf8);
318
319                         MEM_freeN(short_locale_utf8);
320                 }
321                 else {
322                         if (G.debug & G_DEBUG)
323                                 printf("Setting LANG=%s and LANGUAGE=%s\n", default_lang, default_language);
324
325                         BLI_setenv("LANG", default_lang);
326                         BLI_setenv("LANGUAGE", default_language);
327                         locreturn = setlocale(LC_ALL, "");
328
329                         if (G.debug & G_DEBUG && locreturn == NULL)
330                                 printf("Could not reset locale\n");
331                 }
332
333                 if (locreturn == NULL) {
334                         char language[65];
335
336                         get_language(short_locale, default_lang, language, sizeof(language));
337
338                         if (G.debug & G_DEBUG)
339                                 printf("Fallback to LANG=%s and LANGUAGE=%s\n", default_lang, language);
340
341                         /* Fallback to default settings. */
342                         BLI_setenv("LANG", default_lang);
343                         BLI_setenv("LANGUAGE", language);
344
345                         locreturn = setlocale(LC_ALL, "");
346
347                         ok = FALSE;
348                 }
349         }
350 #endif
351
352         if (ok) {
353                 /*printf("Change locale to %s\n", locreturn ); */
354                 BLI_strncpy(global_language, locreturn, sizeof(global_language));
355         }
356
357         setlocale(LC_NUMERIC, "C");
358
359         textdomain(TEXT_DOMAIN_NAME);
360         bindtextdomain(TEXT_DOMAIN_NAME, global_messagepath);
361         bind_textdomain_codeset(TEXT_DOMAIN_NAME, global_encoding_name);
362 }
363
364 const char *BLF_lang_get(void)
365 {
366         int uilang = ULANGUAGE;
367         return LOCALE(uilang);
368 }
369
370 void BLF_lang_encoding(const char *str)
371 {
372         BLI_strncpy(global_encoding_name, str, sizeof(global_encoding_name));
373         /* bind_textdomain_codeset(TEXT_DOMAIN_NAME, encoding_name); */
374 }
375
376 #undef LOCALE
377 #undef ULANGUAGE
378
379 #else /* ! WITH_INTERNATIONAL */
380
381 void BLF_lang_init(void)
382 {
383         return;
384 }
385
386 void BLF_lang_free(void)
387 {
388         return;
389 }
390
391 void BLF_lang_encoding(const char *str)
392 {
393         (void)str;
394         return;
395 }
396
397 void BLF_lang_set(const char *str)
398 {
399         (void)str;
400         return;
401 }
402
403 const char *BLF_lang_get(void)
404 {
405         return "";
406 }
407
408 #endif /* WITH_INTERNATIONAL */