1#include "config.h"
2
3#include <stdlib.h>
4#include <stdio.h>
5
6#ifdef HAVE_UNISTD_H
7#include <unistd.h>
8#endif
9#include <string.h>
10#include <errno.h>
11#include <locale.h>
12#include <sys/stat.h>
13
14#include <glib.h>
15#include <glib/gi18n.h>
16#include <glib/gstdio.h>
17#include <hb-ot.h>
18
19#include "language-names.h"
20
21#ifdef G_OS_WIN32
22#define WIN32_LEAN_AND_MEAN
23#include <windows.h>
24#else
25
26#ifndef ISO_CODES_PREFIX
27#define ISO_CODES_PREFIX "/usr"
28#endif
29
30#define ISO_CODES_DATADIR ISO_CODES_PREFIX "/share/xml/iso-codes"
31#define ISO_CODES_LOCALESDIR ISO_CODES_PREFIX "/share/locale"
32#endif
33
34static GHashTable *language_map;
35
36#ifdef G_OS_WIN32
37/* if we are using native Windows use native Windows API for language names */
38static BOOL CALLBACK
39get_win32_all_locales_scripts (LPWSTR locale_w, DWORD flags, LPARAM param)
40{
41 wchar_t *langname_w = NULL;
42 wchar_t locale_abbrev_w[9];
43 gchar *langname, *locale_abbrev, *locale, *p;
44 gint i;
45 const LCTYPE iso639_lctypes[] = { LOCALE_SISO639LANGNAME, LOCALE_SISO639LANGNAME2 };
46 GHashTable *ht_scripts_langs = (GHashTable *) param;
47 PangoLanguage *lang;
48
49 gint langname_size, locale_abbrev_size;
50 langname_size = GetLocaleInfoEx (locale_w, LOCALE_SLOCALIZEDDISPLAYNAME, langname_w, 0);
51 if (langname_size == 0)
52 return FALSE;
53
54 langname_w = g_new0 (wchar_t, langname_size);
55
56 if (langname_size == 0)
57 return FALSE;
58
59 GetLocaleInfoEx (locale_w, LOCALE_SLOCALIZEDDISPLAYNAME, langname_w, langname_size);
60 langname = g_utf16_to_utf8 (langname_w, -1, NULL, NULL, NULL);
61 locale = g_utf16_to_utf8 (locale_w, -1, NULL, NULL, NULL);
62 p = strchr (locale, '-');
63 lang = pango_language_from_string (locale);
64 if (g_hash_table_lookup (ht_scripts_langs, lang) == NULL)
65 g_hash_table_insert (ht_scripts_langs, lang, langname);
66
67 /*
68 * Track 3+-letter ISO639-2/3 language codes as well (these have a max length of 9 including terminating NUL)
69 * ISO639-2: iso639_lctypes[0] = LOCALE_SISO639LANGNAME
70 * ISO639-3: iso639_lctypes[1] = LOCALE_SISO639LANGNAME2
71 */
72 for (i = 0; i < 2; i++)
73 {
74 locale_abbrev_size = GetLocaleInfoEx (locale_w, iso639_lctypes[i], locale_abbrev_w, 0);
75 if (locale_abbrev_size > 0)
76 {
77 GetLocaleInfoEx (locale_w, iso639_lctypes[i], locale_abbrev_w, locale_abbrev_size);
78
79 locale_abbrev = g_utf16_to_utf8 (locale_abbrev_w, -1, NULL, NULL, NULL);
80 lang = pango_language_from_string (locale_abbrev);
81 if (g_hash_table_lookup (ht_scripts_langs, lang) == NULL)
82 g_hash_table_insert (ht_scripts_langs, lang, langname);
83
84 g_free (locale_abbrev);
85 }
86 }
87
88 g_free (locale);
89 g_free (langname_w);
90
91 return TRUE;
92}
93
94#else /* non-Windows */
95
96static char *
97get_first_item_in_semicolon_list (const char *list)
98{
99 char **items;
100 char *item;
101
102 items = g_strsplit (string: list, delimiter: "; ", max_tokens: 2);
103
104 item = g_strdup (str: items[0]);
105 g_strfreev (str_array: items);
106
107 return item;
108}
109
110static char *
111capitalize_utf8_string (const char *str)
112{
113 char first[8] = { 0 };
114
115 if (!str)
116 return NULL;
117
118 g_unichar_to_utf8 (c: g_unichar_totitle (c: g_utf8_get_char (p: str)), outbuf: first);
119
120 return g_strconcat (string1: first, g_utf8_offset_to_pointer (str, offset: 1), NULL);
121}
122
123static char *
124get_display_name (const char *language)
125{
126 const char *translated;
127 char *tmp;
128 char *name;
129
130 translated = dgettext ("iso_639", language);
131
132 tmp = get_first_item_in_semicolon_list (list: translated);
133 name = capitalize_utf8_string (str: tmp);
134 g_free (mem: tmp);
135
136 return name;
137}
138
139static void
140languages_parse_start_tag (GMarkupParseContext *ctx,
141 const char *element_name,
142 const char **attr_names,
143 const char **attr_values,
144 gpointer user_data,
145 GError **error)
146{
147 const char *ccode_longB;
148 const char *ccode_longT;
149 const char *ccode;
150 const char *ccode_id;
151 const char *lang_name;
152 char *display_name;
153
154 if (!(g_str_equal (v1: element_name, v2: "iso_639_entry") ||
155 g_str_equal (v1: element_name, v2: "iso_639_3_entry")) ||
156 attr_names == NULL ||
157 attr_values == NULL)
158 return;
159
160 ccode = NULL;
161 ccode_longB = NULL;
162 ccode_longT = NULL;
163 ccode_id = NULL;
164 lang_name = NULL;
165
166 while (*attr_names && *attr_values)
167 {
168 if (g_str_equal (v1: *attr_names, v2: "iso_639_1_code"))
169 {
170 if (**attr_values)
171 {
172 if (strlen (s: *attr_values) != 2)
173 return;
174 ccode = *attr_values;
175 }
176 }
177 else if (g_str_equal (v1: *attr_names, v2: "iso_639_2B_code"))
178 {
179 if (**attr_values)
180 {
181 if (strlen (s: *attr_values) != 3)
182 return;
183 ccode_longB = *attr_values;
184 }
185 }
186 else if (g_str_equal (v1: *attr_names, v2: "iso_639_2T_code"))
187 {
188 if (**attr_values)
189 {
190 if (strlen (s: *attr_values) != 3)
191 return;
192 ccode_longT = *attr_values;
193 }
194 }
195 else if (g_str_equal (v1: *attr_names, v2: "id"))
196 {
197 if (**attr_values)
198 {
199 if (strlen (s: *attr_values) != 2 &&
200 strlen (s: *attr_values) != 3)
201 return;
202 ccode_id = *attr_values;
203 }
204 }
205 else if (g_str_equal (v1: *attr_names, v2: "name"))
206 {
207 lang_name = *attr_values;
208 }
209
210 ++attr_names;
211 ++attr_values;
212 }
213
214 if (lang_name == NULL)
215 return;
216
217 display_name = get_display_name (language: lang_name);
218
219 if (ccode != NULL)
220 g_hash_table_insert (hash_table: language_map,
221 key: pango_language_from_string (language: ccode),
222 value: g_strdup (str: display_name));
223
224 if (ccode_longB != NULL)
225 g_hash_table_insert (hash_table: language_map,
226 key: pango_language_from_string (language: ccode_longB),
227 value: g_strdup (str: display_name));
228
229 if (ccode_longT != NULL)
230 g_hash_table_insert (hash_table: language_map,
231 key: pango_language_from_string (language: ccode_longT),
232 value: g_strdup (str: display_name));
233
234 if (ccode_id != NULL)
235 g_hash_table_insert (hash_table: language_map,
236 key: pango_language_from_string (language: ccode_id),
237 value: g_strdup (str: display_name));
238
239 g_free (mem: display_name);
240}
241
242static void
243languages_variant_init (const char *variant)
244{
245 gboolean res;
246 gsize buf_len;
247 char *buf = NULL;
248 char *filename = NULL;
249 GError *error = NULL;
250
251 bindtextdomain (domainname: variant, ISO_CODES_LOCALESDIR);
252 bind_textdomain_codeset (domainname: variant, codeset: "UTF-8");
253
254 error = NULL;
255 filename = g_strconcat (ISO_CODES_DATADIR, "/", variant, ".xml", NULL);
256 res = g_file_get_contents (filename, contents: &buf, length: &buf_len, error: &error);
257 if (res)
258 {
259 GMarkupParseContext *ctx = NULL;
260 GMarkupParser parser = { languages_parse_start_tag, NULL, NULL, NULL, NULL };
261
262 ctx = g_markup_parse_context_new (parser: &parser, flags: 0, NULL, NULL);
263
264 g_free (mem: error);
265 error = NULL;
266 res = g_markup_parse_context_parse (context: ctx, text: buf, text_len: buf_len, error: &error);
267 g_free (mem: ctx);
268
269 if (!res)
270 g_warning ("Failed to parse '%s': %s\n", filename, error->message);
271 }
272 else
273 g_warning ("Failed to load '%s': %s\n", filename, error->message);
274
275 g_clear_error (err: &error);
276 g_free (mem: filename);
277 g_free (mem: buf);
278}
279#endif
280
281static void
282languages_init (void)
283{
284 if (language_map)
285 return;
286
287 language_map = g_hash_table_new_full (NULL, NULL, NULL, value_destroy_func: g_free);
288
289#ifdef G_OS_WIN32
290 g_return_if_fail (EnumSystemLocalesEx (&get_win32_all_locales_scripts, LOCALE_ALL, (LPARAM) language_map, NULL));
291#else
292 languages_variant_init (variant: "iso_639");
293 languages_variant_init (variant: "iso_639_3");
294#endif
295}
296
297const char *
298get_language_name (PangoLanguage *language)
299{
300 languages_init ();
301
302 return (const char *) g_hash_table_lookup (hash_table: language_map, key: language);
303}
304
305const char *
306get_language_name_for_tag (guint32 tag)
307{
308 hb_language_t lang;
309 const char *s;
310
311 lang = hb_ot_tag_to_language (tag);
312 s = hb_language_to_string (language: lang);
313
314 return get_language_name (language: pango_language_from_string (language: s));
315}
316

source code of gtk/demos/gtk-demo/language-names.c