1003ea8e9332a2d388f03f15c160146200107bfc
[platform/core/appfw/app-core.git] / src / appcore-i18n.c
1 /*
2  *  app-core
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Jayoun Lee <airjany@samsung.com>, Sewook Park <sewook7.park@samsung.com>, Jaeho Lee <jaeho81.lee@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22
23 #include <locale.h>
24 #include <libintl.h>
25 #include <stdlib.h>
26 #include <errno.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <unistd.h>
30 #include <linux/limits.h>
31 #include <glib.h>
32 #include <vconf.h>
33
34 #include "appcore-internal.h"
35
36 static int _set;
37 static char locale_dir[PATH_MAX];
38
39 static void __free_children_langs(gpointer data)
40 {
41         GList *list = (GList *)data;
42
43         if (list == NULL)
44                 return;
45
46         g_list_free_full(list, (GDestroyNotify)free);
47 }
48
49 static gint __compare_langs(gconstpointer a, gconstpointer b)
50 {
51         return strcmp(a, b);
52 }
53
54 static GHashTable *__get_lang_table(void)
55 {
56         GHashTable *table;
57         DIR *dp;
58         struct dirent *dentry;
59         char buf[PATH_MAX];
60         struct stat stat_buf;
61         int ret;
62         char *dup_lang;
63         char *token;
64         GList *list;
65
66         if (locale_dir[0] == 0 || locale_dir[0] == '\0')
67                 return NULL;
68
69         table = g_hash_table_new_full(g_str_hash, g_str_equal,
70                         free, __free_children_langs);
71         if (table == NULL) {
72                 _ERR("Out of memory");
73                 return NULL;
74         }
75
76         dp = opendir(locale_dir);
77         if (dp == NULL) {
78                 g_hash_table_destroy(table);
79                 return NULL;
80         }
81
82         while ((dentry = readdir(dp)) != NULL) {
83                 if (!strcmp(dentry->d_name, ".") ||
84                                 !strcmp(dentry->d_name, ".."))
85                         continue;
86
87                 snprintf(buf, sizeof(buf), "%s/%s", locale_dir, dentry->d_name);
88                 ret = stat(buf, &stat_buf);
89                 if (ret != 0 || !S_ISDIR(stat_buf.st_mode))
90                         continue;
91
92                 dup_lang = strdup(dentry->d_name);
93                 if (dup_lang == NULL) {
94                         _ERR("Out of memory");
95                         break;
96                 }
97
98                 token = strtok(dup_lang, "_");
99                 if (token == NULL) {
100                         free(dup_lang);
101                         continue;
102                 }
103
104                 list = (GList *)g_hash_table_lookup(table, token);
105                 if (list == NULL) {
106                         list = g_list_append(list, strdup(dentry->d_name));
107                         g_hash_table_insert(table, strdup(token), list);
108                 } else {
109                         list = g_list_append(list, strdup(dentry->d_name));
110                 }
111                 free(dup_lang);
112         }
113         closedir(dp);
114
115         return table;
116 }
117
118 static char *__get_string_before(const char *str, const char *delim)
119 {
120         char *new_str;
121         char *dup_str;
122         char *token;
123
124         dup_str = strdup(str);
125         if (dup_str == NULL)
126                 return NULL;
127
128         token = strtok(dup_str, delim);
129         if (token == NULL) {
130                 free(dup_str);
131                 return NULL;
132         }
133
134         new_str = strdup(token);
135         free(dup_str);
136
137         return new_str;
138 }
139
140 static GList *__append_langs(const char *lang, GList *list, GHashTable *table)
141 {
142         GList *child_list;
143         GList *child_iter;
144         GList *found;
145         char *child_lang;
146         char *parent_lang;
147         char *extract_lang;
148         char *tmp;
149
150         if (lang == NULL)
151                 return list;
152
153         found = g_list_find_custom(g_list_first(list), lang,
154                         __compare_langs);
155         if (found) {
156                 tmp = (char *)found->data;
157                 list = g_list_remove(list, tmp);
158                 list = g_list_append(list, tmp);
159                 return list;
160         }
161
162         extract_lang = __get_string_before(lang, ".");
163         if (extract_lang == NULL)
164                 return list;
165
166         parent_lang = __get_string_before(extract_lang, "_");
167         if (parent_lang == NULL) {
168                 free(extract_lang);
169                 return list;
170         }
171
172         child_list = g_hash_table_lookup(table, parent_lang);
173         if (child_list == NULL) {
174                 free(parent_lang);
175                 free(extract_lang);
176                 return list;
177         }
178
179         found = g_list_find_custom(g_list_first(child_list),
180                         extract_lang, __compare_langs);
181         if (found) {
182                 tmp = (char *)found->data;
183                 child_list = g_list_remove(child_list, tmp);
184                 list = g_list_append(list, tmp);
185                 free(parent_lang);
186                 free(extract_lang);
187                 return list;
188         }
189         free(extract_lang);
190
191         found = g_list_find_custom(g_list_first(child_list),
192                         parent_lang, __compare_langs);
193         if (found) {
194                 tmp = (char *)found->data;
195                 child_list = g_list_remove(child_list, tmp);
196                 list = g_list_append(list, tmp);
197                 free(parent_lang);
198                 return list;
199         }
200         free(parent_lang);
201
202         child_iter = g_list_first(child_list);
203         while (child_iter) {
204                 child_lang = (char *)child_iter->data;
205                 child_iter = g_list_next(child_iter);
206                 if (child_lang) {
207                         list = g_list_append(list, strdup(child_lang));
208                         child_list = g_list_remove(child_list, child_lang);
209                         free(child_lang);
210                         break;
211                 }
212         }
213
214         return list;
215 }
216
217 static GList *__split_language(const char *lang)
218 {
219         GList *list = NULL;
220         char *dup_lang;
221         char *token;
222
223         dup_lang = strdup(lang);
224         if (dup_lang == NULL) {
225                 _ERR("Out of memory");
226                 return NULL;
227         }
228
229         token = strtok(dup_lang, ":");
230         while (token != NULL) {
231                 list = g_list_append(list, strdup(token));
232                 token = strtok(NULL, ":");
233         }
234         free(dup_lang);
235
236         return list;
237 }
238
239 static GList *__append_default_langs(GList *list)
240 {
241         const char *langs[] = {"en_US", "en_GB", "en"};
242         unsigned int i;
243         GList *found;
244
245         for (i = 0; i < (sizeof(langs) / sizeof(langs[0])); i++) {
246                 found = g_list_find_custom(g_list_first(list), langs[i],
247                                 __compare_langs);
248                 if (found == NULL)
249                         list = g_list_append(list, strdup(langs[i]));
250         }
251
252         return list;
253 }
254
255 static char *__get_language(const char *lang)
256 {
257         GHashTable *table;
258         GList *list;
259         GList *lang_list = NULL;
260         GList *iter;
261         char *language;
262         char buf[LINE_MAX] = {'\0'};
263         size_t n;
264
265         list = __split_language(lang);
266         if (list == NULL)
267                 return NULL;
268
269         table = __get_lang_table();
270         if (table == NULL) {
271                 g_list_free_full(list, free);
272                 return NULL;
273         }
274
275         iter = g_list_first(list);
276         while (iter) {
277                 language = (char *)iter->data;
278                 lang_list = __append_langs(language, lang_list, table);
279                 iter = g_list_next(iter);
280         }
281         g_list_free_full(list, free);
282         g_hash_table_destroy(table);
283
284         lang_list = __append_default_langs(lang_list);
285         iter = g_list_first(lang_list);
286         while (iter) {
287                 language = (char *)iter->data;
288                 if (language) {
289                         if (buf[0] == '\0') {
290                                 snprintf(buf, sizeof(buf), "%s", language);
291                         } else {
292                                 n = sizeof(buf) - strlen(buf) - 1;
293                                 strncat(buf, ":", n);
294                                 n = sizeof(buf) - strlen(buf) - 1;
295                                 strncat(buf, language, n);
296                         }
297                 }
298                 iter = g_list_next(iter);
299         }
300         g_list_free_full(lang_list, free);
301
302         return strdup(buf);
303 }
304
305 void update_lang(void)
306 {
307         char *language;
308         char *lang;
309         char *r;
310
311         lang = vconf_get_str(VCONFKEY_LANGSET);
312         if (lang) {
313                 /* TODO: Use VCONFKEY_SETAPPL_LANGUAGES key */
314                 language = __get_language(lang);
315                 if (language) {
316                         _DBG("*****language(%s)", language);
317                         setenv("LANGUAGE", language, 1);
318                         free(language);
319                 } else {
320                         setenv("LANGUAGE", lang, 1);
321                 }
322                 setenv("LANG", lang, 1);
323                 setenv("LC_MESSAGES", lang, 1);
324                 r = setlocale(LC_ALL, "");
325                 if (r == NULL) {
326                         r = setlocale(LC_ALL, lang);
327                         if (r != NULL)
328                                 _DBG("*****appcore setlocale=%s\n", r);
329                 }
330                 free(lang);
331         }
332 }
333
334 void update_region(void)
335 {
336         char *region;
337         char *r;
338
339         region = vconf_get_str(VCONFKEY_REGIONFORMAT);
340         if (region) {
341                 setenv("LC_CTYPE", region, 1);
342                 setenv("LC_NUMERIC", region, 1);
343                 setenv("LC_TIME", region, 1);
344                 setenv("LC_COLLATE", region, 1);
345                 setenv("LC_MONETARY", region, 1);
346                 setenv("LC_PAPER", region, 1);
347                 setenv("LC_NAME", region, 1);
348                 setenv("LC_ADDRESS", region, 1);
349                 setenv("LC_TELEPHONE", region, 1);
350                 setenv("LC_MEASUREMENT", region, 1);
351                 setenv("LC_IDENTIFICATION", region, 1);
352                 r = setlocale(LC_ALL, "");
353                 if (r != NULL)
354                         _DBG("*****appcore setlocale=%s\n", r);
355
356                 free(region);
357         }
358 }
359
360 static int __set_i18n(const char *domain, const char *dir)
361 {
362         char *r;
363         char *lan;
364
365         if (domain == NULL) {
366                 errno = EINVAL;
367                 return -1;
368         }
369
370         r = setlocale(LC_ALL, "");
371         /* if locale is not set properly, try again to set as language base */
372         if (r == NULL) {
373                 lan = vconf_get_str(VCONFKEY_LANGSET);
374                 if (lan != NULL) {
375                         r = setlocale(LC_ALL, lan);
376                         _DBG("*****appcore setlocale=%s\n", r);
377                         free(lan);
378                 }
379         }
380         if (r == NULL)
381                 _ERR("appcore: setlocale() error");
382
383         r = bindtextdomain(domain, dir);
384         if (r == NULL)
385                 _ERR("appcore: bindtextdomain() error");
386
387         r = textdomain(domain);
388         if (r == NULL)
389                 _ERR("appcore: textdomain() error");
390
391         return 0;
392 }
393
394 static void __set_locale_dir(const char *dirname)
395 {
396         if (dirname == NULL)
397                 return;
398
399         snprintf(locale_dir, sizeof(locale_dir), "%s", dirname);
400 }
401
402 EXPORT_API int appcore_set_i18n(const char *domainname, const char *dirname)
403 {
404         int r;
405
406         __set_locale_dir(dirname);
407         update_lang();
408         update_region();
409
410         r = __set_i18n(domainname, dirname);
411         if (r == 0)
412                 _set = 1;
413
414         return r;
415 }
416
417 int set_i18n(const char *domainname, const char *dirname)
418 {
419         _retv_if(_set, 0);
420
421         __set_locale_dir(dirname);
422         update_lang();
423         update_region();
424
425         return __set_i18n(domainname, dirname);
426 }
427
428 EXPORT_API int appcore_get_timeformat(enum appcore_time_format *timeformat)
429 {
430         int r;
431
432         if (timeformat == NULL) {
433                 errno = EINVAL;
434                 return -1;
435         }
436
437         r = vconf_get_int(VCONFKEY_REGIONFORMAT_TIME1224, (int *)timeformat);
438
439         if (r < 0) {
440                 *timeformat = APPCORE_TIME_FORMAT_UNKNOWN;
441                 return -1;
442         } else
443                 return 0;
444 }