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