9086799f98456cc51bdf28ddc9fb976702d38410
[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 "BLF_translation.h" /* own include */
32
33 #include "BLI_utildefines.h"
34
35 #ifdef WITH_INTERNATIONAL
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40
41 #include "boost_locale_wrapper.h"
42
43 #include "BKE_global.h"
44
45 #include "DNA_userdef_types.h"
46
47 #include "RNA_types.h"
48
49 #include "MEM_guardedalloc.h"
50
51 #include "BLI_fileops.h"
52 #include "BLI_linklist.h"
53 #include "BLI_path_util.h"
54 #include "BLI_string.h"
55
56 /* Locale options. */
57 static const char **locales = NULL;
58 static int num_locales = 0;
59 static EnumPropertyItem *locales_menu = NULL;
60 static int num_locales_menu = 0;
61
62 #define ULANGUAGE ((U.language >= 0 && U.language < num_locales) ? U.language : 0)
63 #define LOCALE(_id) (locales ? locales[_id] : "")
64
65 static void free_locales(void)
66 {
67         if (locales) {
68                 int idx = num_locales_menu - 1; /* Last item does not need to be freed! */
69                 while (idx--) {
70                         MEM_freeN((void *)locales_menu[idx].identifier);
71                         MEM_freeN((void *)locales_menu[idx].name);
72                         MEM_freeN((void *)locales_menu[idx].description); /* Also frees locales's relevant value! */
73                 }
74
75                 MEM_freeN(locales);
76                 locales = NULL;
77         }
78         if (locales_menu) {
79                 MEM_freeN(locales_menu);
80                 locales_menu = NULL;
81         }
82         num_locales = num_locales_menu = 0;
83 }
84
85 static void fill_locales(void)
86 {
87         char *languages_path = BLI_get_folder(BLENDER_DATAFILES, "locale");
88         LinkNode *lines = NULL, *line;
89         char *str;
90         int idx = 0;
91
92         free_locales();
93
94         BLI_join_dirfile(languages_path, FILE_MAX, languages_path, "languages");
95         line = lines = BLI_file_read_as_lines(languages_path);
96
97         /* This whole "parsing" code is a bit weak, in that it expects strictly formated input file...
98          * Should not be a problem, though, as this file is script-generated! */
99
100         /* First loop to find highest locale ID */
101         while (line) {
102                 int t;
103                 str = (char *)line->link;
104                 if (str[0] == '#' || str[0] == '\0') {
105                         line = line->next;
106                         continue; /* Comment or void... */
107                 }
108                 t = atoi(str);
109                 if (t >= num_locales)
110                         num_locales = t + 1;
111                 num_locales_menu++;
112                 line = line->next;
113         }
114         num_locales_menu++; /* The "closing" void item... */
115
116         /* And now, buil locales and locale_menu! */
117         locales_menu = MEM_callocN(num_locales_menu * sizeof(EnumPropertyItem), __func__);
118         line = lines;
119         /* Do not allocate locales with zero-sized mem, as LOCALE macro uses NULL locales as invalid marker! */
120         if (num_locales > 0) {
121                 locales = MEM_callocN(num_locales * sizeof(char *), __func__);
122                 while (line) {
123                         int id;
124                         char *loc, *sep1, *sep2, *sep3;
125
126                         str = (char *)line->link;
127                         if (str[0] == '#' || str[0] == '\0') {
128                                 line = line->next;
129                                 continue;
130                         }
131
132                         id = atoi(str);
133                         sep1 = strchr(str, ':');
134                         if (sep1) {
135                                 sep1++;
136                                 sep2 = strchr(sep1, ':');
137                                 if (sep2) {
138                                         locales_menu[idx].value = id;
139                                         locales_menu[idx].icon = 0;
140                                         locales_menu[idx].name = BLI_strdupn(sep1, sep2 - sep1);
141
142                                         sep2++;
143                                         sep3 = strchr(sep2, ':');
144
145                                         if (sep3) {
146                                                 locales_menu[idx].identifier = loc = BLI_strdupn(sep2, sep3 - sep2);
147                                         }
148                                         else {
149                                                 locales_menu[idx].identifier = loc = BLI_strdup(sep2);
150                                         }
151
152                                         if (id == 0) {
153                                                 /* The DEFAULT item... */
154                                                 if (BLI_strnlen(loc, 2)) {
155                                                         locales[id] = locales_menu[idx].description = BLI_strdup("");
156                                                 }
157                                                 /* Menu "label", not to be stored in locales! */
158                                                 else {
159                                                         locales_menu[idx].description = BLI_strdup("");
160                                                 }
161                                         }
162                                         else {
163                                                 locales[id] = locales_menu[idx].description = BLI_strdup(loc);
164                                         }
165                                         idx++;
166                                 }
167                         }
168
169                         line = line->next;
170                 }
171         }
172
173         /* Add closing item to menu! */
174         locales_menu[idx].identifier = NULL;
175         locales_menu[idx].value = locales_menu[idx].icon = 0;
176         locales_menu[idx].name = locales_menu[idx].description = "";
177
178         BLI_file_free_lines(lines);
179 }
180
181 EnumPropertyItem *BLF_RNA_lang_enum_properties(void)
182 {
183         return locales_menu;
184 }
185
186 void BLF_lang_init(void)
187 {
188         char *messagepath = BLI_get_folder(BLENDER_DATAFILES, "locale");
189
190         if (messagepath) {
191                 bl_locale_init(messagepath, TEXT_DOMAIN_NAME);
192                 fill_locales();
193         }
194         else {
195                 printf("%s: 'locale' data path for translations not found, continuing\n", __func__);
196         }
197 }
198
199 void BLF_lang_free(void)
200 {
201         free_locales();
202 }
203
204 void BLF_lang_set(const char *str)
205 {
206         int ulang = ULANGUAGE;
207         const char *short_locale = str ? str : LOCALE(ulang);
208         const char *short_locale_utf8 = NULL;
209
210         if ((U.transopts & USER_DOTRANSLATE) == 0)
211                 return;
212
213         /* We want to avoid locales like '.UTF-8'! */
214         if (short_locale[0]) {
215                 /* Hurrey! encoding needs to be placed *before* variant! */
216                 char *variant = strchr(short_locale, '@');
217                 if (variant) {
218                         char *locale = BLI_strdupn(short_locale, variant - short_locale);
219                         short_locale_utf8 = BLI_sprintfN("%s.UTF-8%s", locale, variant);
220                         MEM_freeN(locale);
221                 }
222                 else {
223                         short_locale_utf8 = BLI_sprintfN("%s.UTF-8", short_locale);
224                 }
225         }
226         else {
227                 short_locale_utf8 = short_locale;
228         }
229
230         bl_locale_set(short_locale_utf8);
231
232         if (short_locale[0]) {
233                 MEM_freeN((void *)short_locale_utf8);
234         }
235 }
236
237 const char *BLF_lang_get(void)
238 {
239         int uilang = ULANGUAGE;
240         return LOCALE(uilang);
241 }
242
243 #undef LOCALE
244 #undef ULANGUAGE
245
246 #else /* ! WITH_INTERNATIONAL */
247
248 void BLF_lang_init(void)
249 {
250         return;
251 }
252
253 void BLF_lang_free(void)
254 {
255         return;
256 }
257
258 void BLF_lang_set(const char *UNUSED(str))
259 {
260         return;
261 }
262
263 const char *BLF_lang_get(void)
264 {
265         return "";
266 }
267
268 #endif /* WITH_INTERNATIONAL */