1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2004-2007 Imendio AB
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public
16 * License along with this program; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301 USA
20 * Authors: Martyn Russell <martyn@imendio.com>
21 * Richard Hult <richard@imendio.com>
25 #include "empathy-spell.h"
27 #include <glib/gi18n-lib.h>
33 #include "empathy-gsettings.h"
35 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
36 #include "empathy-debug.h"
41 EnchantBroker
*config
;
45 #define ISO_CODES_DATADIR ISO_CODES_PREFIX "/share/xml/iso-codes"
46 #define ISO_CODES_LOCALESDIR ISO_CODES_PREFIX "/share/locale"
48 /* Language code (gchar *) -> language name (gchar *) */
49 static GHashTable
*iso_code_names
= NULL
;
50 /* Contains only _enabled_ languages
51 * Language code (gchar *) -> language (SpellLanguage *) */
52 static GHashTable
*languages
= NULL
;
55 spell_iso_codes_parse_start_tag (GMarkupParseContext
*ctx
,
56 const gchar
*element_name
,
57 const gchar
**attr_names
,
58 const gchar
**attr_values
,
62 const gchar
*ccode_longB
, *ccode_longT
, *ccode
;
63 const gchar
*lang_name
;
65 if (!g_str_equal (element_name
, "iso_639_entry") ||
66 attr_names
== NULL
|| attr_values
== NULL
) {
75 while (*attr_names
&& *attr_values
) {
76 if (g_str_equal (*attr_names
, "iso_639_1_code")) {
81 else if (g_str_equal (*attr_names
, "iso_639_2B_code")) {
83 ccode_longB
= *attr_values
;
86 else if (g_str_equal (*attr_names
, "iso_639_2T_code")) {
88 ccode_longT
= *attr_values
;
91 else if (g_str_equal (*attr_names
, "name")) {
92 lang_name
= *attr_values
;
104 g_hash_table_insert (iso_code_names
,
106 g_strdup (lang_name
));
110 g_hash_table_insert (iso_code_names
,
111 g_strdup (ccode_longB
),
112 g_strdup (lang_name
));
116 g_hash_table_insert (iso_code_names
,
117 g_strdup (ccode_longT
),
118 g_strdup (lang_name
));
123 spell_iso_code_names_init (void)
129 iso_code_names
= g_hash_table_new_full (g_str_hash
, g_str_equal
,
132 bindtextdomain ("iso_639", ISO_CODES_LOCALESDIR
);
133 bind_textdomain_codeset ("iso_639", "UTF-8");
135 /* FIXME: We should read this in chunks and pass to the parser. */
136 if (g_file_get_contents (ISO_CODES_DATADIR
"/iso_639.xml", &buf
, &buf_len
, &err
)) {
137 GMarkupParseContext
*ctx
;
138 GMarkupParser parser
= {
139 spell_iso_codes_parse_start_tag
,
140 NULL
, NULL
, NULL
, NULL
143 ctx
= g_markup_parse_context_new (&parser
, 0, NULL
, NULL
);
144 if (!g_markup_parse_context_parse (ctx
, buf
, buf_len
, &err
)) {
145 g_warning ("Failed to parse '%s': %s",
146 ISO_CODES_DATADIR
"/iso_639.xml",
151 g_markup_parse_context_free (ctx
);
154 g_warning ("Failed to load '%s': %s",
155 ISO_CODES_DATADIR
"/iso_639.xml", err
->message
);
161 spell_notify_languages_cb (GSettings
*gsettings
,
165 DEBUG ("Resetting languages due to config change");
167 /* We just reset the languages list. */
168 if (languages
!= NULL
) {
169 g_hash_table_unref (languages
);
175 empathy_spell_free_language (SpellLanguage
*lang
)
177 enchant_broker_free_dict (lang
->config
, lang
->speller
);
178 enchant_broker_free (lang
->config
);
180 g_slice_free (SpellLanguage
, lang
);
184 spell_setup_languages (void)
186 static GSettings
*gsettings
= NULL
;
189 if (gsettings
== NULL
) {
190 /* FIXME: this is never uninitialised */
191 gsettings
= g_settings_new (EMPATHY_PREFS_CHAT_SCHEMA
);
193 g_signal_connect (gsettings
,
194 "changed::" EMPATHY_PREFS_CHAT_SPELL_CHECKER_LANGUAGES
,
195 G_CALLBACK (spell_notify_languages_cb
), NULL
);
202 languages
= g_hash_table_new_full (g_str_hash
, g_str_equal
,
203 g_free
, (GDestroyNotify
) empathy_spell_free_language
);
205 str
= g_settings_get_string (gsettings
,
206 EMPATHY_PREFS_CHAT_SPELL_CHECKER_LANGUAGES
);
212 strv
= g_strsplit (str
, ",", -1);
215 while (strv
&& strv
[i
]) {
218 DEBUG ("Setting up language:'%s'", strv
[i
]);
220 lang
= g_slice_new0 (SpellLanguage
);
222 lang
->config
= enchant_broker_init ();
223 lang
->speller
= enchant_broker_request_dict (lang
->config
, strv
[i
]);
225 if (lang
->speller
== NULL
) {
226 DEBUG ("language '%s' has no valid dict", strv
[i
]);
228 g_hash_table_insert (languages
,
245 empathy_spell_get_language_name (const gchar
*code
)
249 g_return_val_if_fail (code
!= NULL
, NULL
);
251 if (!iso_code_names
) {
252 spell_iso_code_names_init ();
255 name
= g_hash_table_lookup (iso_code_names
, code
);
260 return dgettext ("iso_639", name
);
264 enumerate_dicts (const gchar
* const lang_tag
,
265 const gchar
* const provider_name
,
266 const gchar
* const provider_desc
,
267 const gchar
* const provider_file
,
270 GList
**list
= user_data
;
271 gchar
*lang
= g_strdup (lang_tag
);
273 if (strchr (lang
, '_')) {
274 /* cut country part out of language */
275 strchr (lang
, '_')[0] = '\0';
278 if (g_list_find_custom (*list
, lang
, (GCompareFunc
) strcmp
)) {
279 /* this language is already part of the list */
284 *list
= g_list_append (*list
, lang
);
288 empathy_spell_get_language_codes (void)
290 EnchantBroker
*broker
;
291 GList
*list_langs
= NULL
;
293 broker
= enchant_broker_init ();
294 enchant_broker_list_dicts (broker
, enumerate_dicts
, &list_langs
);
295 enchant_broker_free (broker
);
301 empathy_spell_get_enabled_language_codes (void)
303 spell_setup_languages ();
304 return g_hash_table_get_keys (languages
);
308 empathy_spell_free_language_codes (GList
*codes
)
310 g_list_foreach (codes
, (GFunc
) g_free
, NULL
);
315 empathy_spell_check (const gchar
*word
)
317 gint enchant_result
= 1;
325 g_return_val_if_fail (word
!= NULL
, FALSE
);
327 spell_setup_languages ();
333 /* Ignore certain cases like numbers, etc. */
334 for (p
= word
, digit
= TRUE
; *p
&& digit
; p
= g_utf8_next_char (p
)) {
335 c
= g_utf8_get_char (p
);
336 digit
= g_unichar_isdigit (c
);
340 /* We don't spell check digits. */
341 DEBUG ("Not spell checking word:'%s', it is all digits", word
);
346 g_hash_table_iter_init (&iter
, languages
);
347 while (g_hash_table_iter_next (&iter
, NULL
, (gpointer
*) &lang
)) {
348 enchant_result
= enchant_dict_check (lang
->speller
, word
, len
);
350 if (enchant_result
== 0) {
355 return (enchant_result
== 0);
359 empathy_spell_get_suggestions (const gchar
*code
,
363 GList
*suggestion_list
= NULL
;
366 gsize i
, number_of_suggestions
;
368 g_return_val_if_fail (code
!= NULL
, NULL
);
369 g_return_val_if_fail (word
!= NULL
, NULL
);
371 spell_setup_languages ();
379 lang
= g_hash_table_lookup (languages
, code
);
384 suggestions
= enchant_dict_suggest (lang
->speller
, word
, len
,
385 &number_of_suggestions
);
387 for (i
= 0; i
< number_of_suggestions
; i
++) {
388 suggestion_list
= g_list_append (suggestion_list
,
389 g_strdup (suggestions
[i
]));
393 enchant_dict_free_string_list (lang
->speller
, suggestions
);
396 return suggestion_list
;
400 empathy_spell_supported (void)
402 if (g_getenv ("EMPATHY_SPELL_DISABLED")) {
403 DEBUG ("EMPATHY_SPELL_DISABLE env variable defined");
411 empathy_spell_add_to_dictionary (const gchar
*code
,
416 g_return_if_fail (code
!= NULL
);
417 g_return_if_fail (word
!= NULL
);
419 spell_setup_languages ();
420 if (languages
== NULL
)
423 lang
= g_hash_table_lookup (languages
, code
);
427 enchant_dict_add_to_pwl (lang
->speller
, word
, strlen (word
));
430 #else /* not HAVE_ENCHANT */
433 empathy_spell_supported (void)
439 empathy_spell_get_suggestions (const gchar
*code
,
442 DEBUG ("Support disabled, could not get suggestions");
448 empathy_spell_check (const gchar
*word
)
450 DEBUG ("Support disabled, could not check spelling");
456 empathy_spell_get_language_name (const gchar
*lang
)
458 DEBUG ("Support disabled, could not get language name");
464 empathy_spell_get_language_codes (void)
466 DEBUG ("Support disabled, could not get language codes");
472 empathy_spell_free_language_codes (GList
*codes
)
477 empathy_spell_add_to_dictionary (const gchar
*code
,
480 DEBUG ("Support disabled, could not expand the dictionary");
484 empathy_spell_get_enabled_language_codes (void)
486 DEBUG ("Support disabled, could not get enabled language codes");
491 #endif /* HAVE_ENCHANT */
495 empathy_spell_free_suggestions (GList
*suggestions
)
497 g_list_foreach (suggestions
, (GFunc
) g_free
, NULL
);
498 g_list_free (suggestions
);