1 /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
2 /* vim:set et sts=4: */
3 /* bus - The Input Bus
4  * Copyright (C) 2008-2015 Peng Huang <shawn.p.huang@gmail.com>
5  * Copyright (C) 2010-2019 Takao Fujiwara <takao.fujiwara1@gmail.com>
6  * Copyright (C) 2008-2016 Red Hat, Inc.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
21  * USA
22  */
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 #include <glib.h>
28 #include <glib/gstdio.h>
29 #include <gio/gio.h>
30 #include <string.h>
31 #include "ibusxml.h"
32 
33 #ifdef ENABLE_NLS
34 #include <libintl.h>
35 #endif
36 
37 /* gettext macro */
38 #define N_(t) t
39 
40 static GHashTable *__languages_dict;
41 
42 static gboolean
_iso_codes_parse_xml_node(XMLNode * node)43 _iso_codes_parse_xml_node (XMLNode          *node)
44 {
45     GList *p;
46     g_assert (node);
47 
48     if (G_UNLIKELY (g_strcmp0 (node->name, "iso_639_3_entries") != 0)) {
49         return FALSE;
50     }
51 
52     for (p = node->sub_nodes; p != NULL; p = p->next) {
53         XMLNode *sub_node = (XMLNode *)p->data;
54         gchar **attributes = NULL;
55         int i, j;
56         gboolean has_common_name = FALSE;
57         struct {
58             const gchar *key;
59             gchar *value;
60         } entries[] = {
61             { "id", NULL },
62             { "part1_code", NULL },
63             { "part2_code", NULL },
64         };
65 
66         if (sub_node->attributes == NULL) {
67             continue;
68         }
69 
70         attributes = sub_node->attributes;
71         for (i = 0; attributes[i]; i += 2) {
72             if (!g_strcmp0 (attributes[i], "common_name")) {
73                 for (j = 0; j < G_N_ELEMENTS (entries); j++) {
74                     if (entries[j].value == NULL)
75                         continue;
76                     g_hash_table_replace (__languages_dict,
77                                           g_strdup (entries[j].value),
78                                           g_strdup (attributes[i + 1]));
79                 }
80                 has_common_name = TRUE;
81             } else if (!g_strcmp0 (attributes[i], "name")) {
82                 if (has_common_name)
83                     continue;
84                 for (j = 0; j < G_N_ELEMENTS (entries); j++) {
85                     if (entries[j].value == NULL)
86                         continue;
87                     g_hash_table_replace (__languages_dict,
88                                           g_strdup (entries[j].value),
89                                           g_strdup (attributes[i + 1]));
90                 }
91             } else {
92                 for (j = 0; j < G_N_ELEMENTS (entries); j++) {
93                     if (g_strcmp0 (attributes[i], entries[j].key) == 0 &&
94                         attributes[i + 1] != NULL) {
95                         entries[j].value = attributes[i + 1];
96                     }
97                 }
98             }
99         }
100     }
101 
102     return TRUE;
103 }
104 
105 void
_load_lang()106 _load_lang()
107 {
108     gchar *filename;
109     XMLNode *node;
110     struct stat buf;
111 
112 #ifdef ENABLE_NLS
113     bindtextdomain ("iso_639_3", LOCALEDIR);
114     bind_textdomain_codeset ("iso_639_3", "UTF-8");
115 #endif
116 
117     __languages_dict = g_hash_table_new_full (g_str_hash,
118             g_str_equal, g_free, g_free);
119     filename = g_build_filename (ISOCODES_PREFIX,
120                                  "share/xml/iso-codes/iso_639_3.xml",
121                                  NULL);
122     if (g_stat (filename, &buf) != 0) {
123         g_warning ("Can not get stat of file %s", filename);
124         g_free (filename);
125         return;
126     }
127 
128     node = ibus_xml_parse_file (filename);
129     g_free (filename);
130 
131     if (!node) {
132         return;
133     }
134 
135     _iso_codes_parse_xml_node (node);
136     ibus_xml_free (node);
137 }
138 
139 const static gchar *
ibus_get_untranslated_raw_language_name(const gchar * _locale)140 ibus_get_untranslated_raw_language_name (const gchar *_locale)
141 {
142     const gchar *retval;
143     gchar *p = NULL;
144     gchar *lang = NULL;
145 
146     if (__languages_dict == NULL )
147         _load_lang();
148     if ((p = strchr (_locale, '_')) !=  NULL)
149         p = g_strndup (_locale, p - _locale);
150     else
151         p = g_strdup (_locale);
152     lang = g_ascii_strdown (p, -1);
153     g_free (p);
154     retval = (const gchar *) g_hash_table_lookup (__languages_dict, lang);
155     g_free (lang);
156     if (retval != NULL)
157         return retval;
158     else
159         return "Other";
160 }
161 
162 static char *
get_first_item_in_semicolon_list(const char * list)163 get_first_item_in_semicolon_list (const char *list)
164 {
165         char **items;
166         char  *item;
167 
168         items = g_strsplit (list, "; ", 2);
169 
170         item = g_strdup (items[0]);
171         g_strfreev (items);
172 
173         return item;
174 }
175 
176 static char *
capitalize_utf8_string(const char * str)177 capitalize_utf8_string (const char *str)
178 {
179     char first[8] = { 0 };
180 
181     if (!str)
182         return NULL;
183 
184     g_unichar_to_utf8 (g_unichar_totitle (g_utf8_get_char (str)), first);
185 
186     return g_strconcat (first, g_utf8_offset_to_pointer (str, 1), NULL);
187 }
188 
189 gchar *
ibus_get_untranslated_language_name(const gchar * _locale)190 ibus_get_untranslated_language_name (const gchar *_locale)
191 {
192     const gchar *raw = ibus_get_untranslated_raw_language_name (_locale);
193     gchar *tmp = get_first_item_in_semicolon_list (raw);
194     gchar *retval = capitalize_utf8_string (tmp);
195     g_free (tmp);
196     return retval;
197 }
198 
199 gchar *
ibus_get_language_name(const gchar * _locale)200 ibus_get_language_name (const gchar *_locale)
201 {
202     const gchar *raw = ibus_get_untranslated_raw_language_name (_locale);
203     const gchar *translation = NULL;
204     gchar *tmp;
205     gchar *retval;
206 
207 #ifdef ENABLE_NLS
208     if (g_strcmp0 (raw, "Other") == 0)
209         return g_strdup (dgettext (GETTEXT_PACKAGE, N_("Other")));
210     else
211         translation = dgettext ("iso_639_3", raw);
212 #else
213     translation = raw;
214 #endif
215 
216     tmp = get_first_item_in_semicolon_list (translation);
217     retval = capitalize_utf8_string (tmp);
218     g_free (tmp);
219     return retval;
220 }
221 
222 void
ibus_g_variant_get_child_string(GVariant * variant,gsize index,char ** str)223 ibus_g_variant_get_child_string (GVariant *variant, gsize index, char **str)
224 {
225     g_return_if_fail (str != NULL);
226 
227     g_free (*str);
228     g_variant_get_child (variant, index, "s", str);
229 }
230