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
10#include <string.h>
11#include <errno.h>
12#include <locale.h>
13#include <sys/stat.h>
14
15#include <glib.h>
16#include <glib/gi18n.h>
17#include <glib/gstdio.h>
18#include <hb-ot.h>
19
20#include "language-names.h"
21
22#ifdef G_OS_WIN32
23#define WIN32_LEAN_AND_MEAN
24#include <windows.h>
25#else
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 const char *long_names[] = {
154 "Dogri",
155 "Greek, Modern",
156 "Interlingua",
157 "Konkani",
158 "Tonga",
159 "Turkish, Ottoman",
160 };
161 int i;
162
163 if (!(g_str_equal (v1: element_name, v2: "iso_639_entry") ||
164 g_str_equal (v1: element_name, v2: "iso_639_3_entry")) ||
165 attr_names == NULL ||
166 attr_values == NULL)
167 return;
168
169 ccode = NULL;
170 ccode_longB = NULL;
171 ccode_longT = NULL;
172 ccode_id = NULL;
173 lang_name = NULL;
174
175 while (*attr_names && *attr_values)
176 {
177 if (g_str_equal (v1: *attr_names, v2: "iso_639_1_code"))
178 {
179 if (**attr_values)
180 {
181 if (strlen (s: *attr_values) != 2)
182 return;
183 ccode = *attr_values;
184 }
185 }
186 else if (g_str_equal (v1: *attr_names, v2: "iso_639_2B_code"))
187 {
188 if (**attr_values)
189 {
190 if (strlen (s: *attr_values) != 3)
191 return;
192 ccode_longB = *attr_values;
193 }
194 }
195 else if (g_str_equal (v1: *attr_names, v2: "iso_639_2T_code"))
196 {
197 if (**attr_values)
198 {
199 if (strlen (s: *attr_values) != 3)
200 return;
201 ccode_longT = *attr_values;
202 }
203 }
204 else if (g_str_equal (v1: *attr_names, v2: "id"))
205 {
206 if (**attr_values)
207 {
208 if (strlen (s: *attr_values) != 2 &&
209 strlen (s: *attr_values) != 3)
210 return;
211 ccode_id = *attr_values;
212 }
213 }
214 else if (g_str_equal (v1: *attr_names, v2: "name"))
215 {
216 lang_name = *attr_values;
217 }
218
219 ++attr_names;
220 ++attr_values;
221 }
222
223 if (lang_name == NULL)
224 return;
225
226 display_name = get_display_name (language: lang_name);
227
228 /* Fix up some egregious names */
229 for (i = 0; i < G_N_ELEMENTS (long_names); i++)
230 {
231 if (g_str_has_prefix (str: display_name, prefix: long_names[i]))
232 display_name[strlen (s: long_names[i])] = '\0';
233 }
234
235
236 if (ccode != NULL)
237 g_hash_table_insert (hash_table: language_map,
238 key: pango_language_from_string (language: ccode),
239 value: g_strdup (str: display_name));
240
241 if (ccode_longB != NULL)
242 g_hash_table_insert (hash_table: language_map,
243 key: pango_language_from_string (language: ccode_longB),
244 value: g_strdup (str: display_name));
245
246 if (ccode_longT != NULL)
247 g_hash_table_insert (hash_table: language_map,
248 key: pango_language_from_string (language: ccode_longT),
249 value: g_strdup (str: display_name));
250
251 if (ccode_id != NULL)
252 g_hash_table_insert (hash_table: language_map,
253 key: pango_language_from_string (language: ccode_id),
254 value: g_strdup (str: display_name));
255
256 g_free (mem: display_name);
257}
258
259static void
260languages_variant_init (const char *variant)
261{
262 gboolean res;
263 gsize buf_len;
264 char *buf;
265 char *filename;
266 GError *error;
267
268 bindtextdomain (domainname: variant, ISO_CODES_LOCALESDIR);
269 bind_textdomain_codeset (domainname: variant, codeset: "UTF-8");
270
271 error = NULL;
272 filename = g_strconcat (ISO_CODES_DATADIR, "/", variant, ".xml", NULL);
273 res = g_file_get_contents (filename, contents: &buf, length: &buf_len, error: &error);
274 if (res)
275 {
276 GMarkupParseContext *ctx = NULL;
277 GMarkupParser parser = { languages_parse_start_tag, NULL, NULL, NULL, NULL };
278
279 ctx = g_markup_parse_context_new (parser: &parser, flags: 0, NULL, NULL);
280
281 res = g_markup_parse_context_parse (context: ctx, text: buf, text_len: buf_len, error: &error);
282 g_free (mem: ctx);
283
284 if (!res)
285 {
286 g_warning ("Failed to parse '%s': %s\n", filename, error->message);
287 g_error_free (error);
288 }
289 }
290 else
291 {
292 g_warning ("Failed to load '%s': %s\n", filename, error->message);
293 g_error_free (error);
294 }
295
296 g_free (mem: filename);
297 g_free (mem: buf);
298}
299
300#endif
301
302static void
303languages_init (void)
304{
305 if (language_map)
306 return;
307
308 language_map = g_hash_table_new_full (NULL, NULL, NULL, value_destroy_func: g_free);
309
310#ifdef G_OS_WIN32
311 g_return_if_fail (EnumSystemLocalesEx (&get_win32_all_locales_scripts, LOCALE_ALL, (LPARAM) language_map, NULL));
312#else
313 languages_variant_init (variant: "iso_639");
314 languages_variant_init (variant: "iso_639_3");
315#endif
316}
317
318const char *
319get_language_name (PangoLanguage *language)
320{
321 languages_init ();
322
323 return (const char *) g_hash_table_lookup (hash_table: language_map, key: language);
324}
325
326const char *
327get_language_name_for_tag (guint32 tag)
328{
329 hb_language_t lang;
330 const char *s;
331
332 lang = hb_ot_tag_to_language (tag);
333 s = hb_language_to_string (language: lang);
334
335 return get_language_name (language: pango_language_from_string (language: s));
336}
337

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