Updated Spanish translation
[evolution.git] / e-util / e-spell-dictionary.c
blob6b221ab49b4a38dd34ed90200bc6ac3d27580e3a
1 /*
2 * e-spell-dictionary.c
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of version 2 of the GNU Lesser General Public
6 * License as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this program; if not, write to the
15 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 * Boston, MA 02111-1307, USA.
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
23 #include "e-util-private.h"
24 #include "e-spell-dictionary.h"
25 #include "e-spell-checker.h"
27 #include <glib/gi18n-lib.h>
28 #include <string.h>
30 #define E_SPELL_DICTIONARY_GET_PRIVATE(obj) \
31 (G_TYPE_INSTANCE_GET_PRIVATE \
32 ((obj), E_TYPE_SPELL_DICTIONARY, ESpellDictionaryPrivate))
34 /**
35 * ESpellDictionary:
37 * The #ESpellDictionary is a wrapper around #EnchantDict.
40 enum {
41 PROP_0,
42 PROP_SPELL_CHECKER
45 struct _ESpellDictionaryPrivate {
46 GWeakRef spell_checker;
48 gchar *name;
49 gchar *code;
50 gchar *collate_key;
53 #define ISO_639_DOMAIN "iso_639"
54 #define ISO_3166_DOMAIN "iso_3166"
56 static GHashTable *iso_639_table = NULL;
57 static GHashTable *iso_3166_table = NULL;
59 G_DEFINE_TYPE (
60 ESpellDictionary,
61 e_spell_dictionary,
62 G_TYPE_OBJECT);
64 #ifdef HAVE_ISO_CODES
66 #define ISOCODESLOCALEDIR ISO_CODES_PREFIX "/share/locale"
68 #ifdef G_OS_WIN32
69 #ifdef DATADIR
70 #undef DATADIR
71 #endif
72 #include <shlobj.h>
74 static gchar *
75 _get_iso_codes_prefix (void)
77 static gchar retval[1000];
78 static gint beenhere = 0;
79 gchar *temp_dir = 0;
81 if (beenhere)
82 return retval;
84 if (!(temp_dir = g_win32_get_package_installation_directory_of_module (_e_get_dll_hmodule ()))) {
85 strcpy (retval, ISO_CODES_PREFIX);
86 return retval;
89 strcpy (retval, temp_dir);
90 g_free (temp_dir);
91 beenhere = 1;
92 return retval;
95 static gchar *
96 _get_isocodeslocaledir (void)
98 static gchar retval[1000];
99 static gint beenhere = 0;
101 if (beenhere)
102 return retval;
104 strcpy (retval, _get_iso_codes_prefix ());
105 strcat (retval, "\\share\\locale" );
106 beenhere = 1;
107 return retval;
110 #undef ISO_CODES_PREFIX
111 #define ISO_CODES_PREFIX _get_iso_codes_prefix ()
113 #undef ISOCODESLOCALEDIR
114 #define ISOCODESLOCALEDIR _get_isocodeslocaledir ()
116 #endif
118 static void
119 iso_639_start_element (GMarkupParseContext *context,
120 const gchar *element_name,
121 const gchar **attribute_names,
122 const gchar **attribute_values,
123 gpointer data,
124 GError **error)
126 GHashTable *hash_table = data;
127 const gchar *iso_639_1_code = NULL;
128 const gchar *iso_639_2_code = NULL;
129 const gchar *name = NULL;
130 const gchar *code = NULL;
131 gint ii;
133 if (g_strcmp0 (element_name, "iso_639_entry") != 0) {
134 return;
137 for (ii = 0; attribute_names[ii] != NULL; ii++) {
138 if (strcmp (attribute_names[ii], "name") == 0)
139 name = attribute_values[ii];
140 else if (strcmp (attribute_names[ii], "iso_639_1_code") == 0)
141 iso_639_1_code = attribute_values[ii];
142 else if (strcmp (attribute_names[ii], "iso_639_2T_code") == 0)
143 iso_639_2_code = attribute_values[ii];
146 code = (iso_639_1_code != NULL) ? iso_639_1_code : iso_639_2_code;
148 if (code != NULL && *code != '\0' && name != NULL && *name != '\0')
149 g_hash_table_insert (
150 hash_table, g_strdup (code),
151 g_strdup (dgettext (ISO_639_DOMAIN, name)));
154 static void
155 iso_3166_start_element (GMarkupParseContext *context,
156 const gchar *element_name,
157 const gchar **attribute_names,
158 const gchar **attribute_values,
159 gpointer data,
160 GError **error)
162 GHashTable *hash_table = data;
163 const gchar *name = NULL;
164 const gchar *code = NULL;
165 gint ii;
167 if (strcmp (element_name, "iso_3166_entry") != 0)
168 return;
170 for (ii = 0; attribute_names[ii] != NULL; ii++) {
171 if (strcmp (attribute_names[ii], "name") == 0)
172 name = attribute_values[ii];
173 else if (strcmp (attribute_names[ii], "alpha_2_code") == 0)
174 code = attribute_values[ii];
177 if (code != NULL && *code != '\0' && name != NULL && *name != '\0')
178 g_hash_table_insert (
179 hash_table, g_ascii_strdown (code, -1),
180 g_strdup (dgettext (ISO_3166_DOMAIN, name)));
183 static GMarkupParser iso_639_parser = {
184 iso_639_start_element,
185 NULL, NULL, NULL, NULL
188 static GMarkupParser iso_3166_parser = {
189 iso_3166_start_element,
190 NULL, NULL, NULL, NULL
193 static void
194 iso_codes_parse (const GMarkupParser *parser,
195 const gchar *basename,
196 GHashTable *hash_table)
198 GMappedFile *mapped_file;
199 gchar *filename;
200 GError *error = NULL;
202 filename = g_build_filename (
203 ISO_CODES_PREFIX, "share", "xml",
204 "iso-codes", basename, NULL);
205 mapped_file = g_mapped_file_new (filename, FALSE, &error);
206 g_free (filename);
208 if (mapped_file != NULL) {
209 GMarkupParseContext *context;
210 const gchar *contents;
211 gsize length;
213 context = g_markup_parse_context_new (
214 parser, 0, hash_table, NULL);
215 contents = g_mapped_file_get_contents (mapped_file);
216 length = g_mapped_file_get_length (mapped_file);
217 g_markup_parse_context_parse (
218 context, contents, length, &error);
219 g_markup_parse_context_free (context);
220 #if GLIB_CHECK_VERSION(2,21,3)
221 g_mapped_file_unref (mapped_file);
222 #else
223 g_mapped_file_free (mapped_file);
224 #endif
227 if (error != NULL) {
228 g_warning ("%s: %s", basename, error->message);
229 g_error_free (error);
233 #endif /* HAVE_ISO_CODES */
235 struct _enchant_dict_description_data {
236 gchar *language_tag;
237 gchar *dict_name;
240 static void
241 describe_dictionary (const gchar *language_tag,
242 const gchar *provider_name,
243 const gchar *provider_desc,
244 const gchar *provider_file,
245 gpointer user_data)
247 struct _enchant_dict_description_data *data = user_data;
248 const gchar *iso_639_name;
249 const gchar *iso_3166_name;
250 gchar *language_name;
251 gchar *lowercase;
252 gchar **tokens;
254 /* Split language code into lowercase tokens. */
255 lowercase = g_ascii_strdown (language_tag, -1);
256 tokens = g_strsplit (lowercase, "_", -1);
257 g_free (lowercase);
259 g_return_if_fail (tokens != NULL);
261 iso_639_name = g_hash_table_lookup (iso_639_table, tokens[0]);
263 if (iso_639_name == NULL) {
264 language_name = g_strdup_printf (
265 /* Translators: %s is the language ISO code. */
266 C_("language", "Unknown (%s)"), language_tag);
267 goto exit;
270 if (g_strv_length (tokens) < 2) {
271 language_name = g_strdup (iso_639_name);
272 goto exit;
275 iso_3166_name = g_hash_table_lookup (iso_3166_table, tokens[1]);
277 if (iso_3166_name != NULL)
278 language_name = g_strdup_printf (
279 /* Translators: The first %s is the language name, and the
280 * second is the country name. Example: "French (France)" */
281 C_("language", "%s (%s)"), iso_639_name, iso_3166_name);
282 else
283 language_name = g_strdup_printf (
284 /* Translators: The first %s is the language name, and the
285 * second is the country name. Example: "French (France)" */
286 C_("language", "%s (%s)"), iso_639_name, tokens[1]);
288 exit:
289 g_strfreev (tokens);
291 data->language_tag = g_strdup (language_tag);
292 data->dict_name = language_name;
295 static void
296 spell_dictionary_set_enchant_dict (ESpellDictionary *dictionary,
297 EnchantDict *enchant_dict)
299 struct _enchant_dict_description_data data;
301 enchant_dict_describe (enchant_dict, describe_dictionary, &data);
303 dictionary->priv->code = data.language_tag;
304 dictionary->priv->name = data.dict_name;
305 dictionary->priv->collate_key = g_utf8_collate_key (data.dict_name, -1);
308 static void
309 spell_dictionary_set_spell_checker (ESpellDictionary *dictionary,
310 ESpellChecker *spell_checker)
312 g_return_if_fail (E_IS_SPELL_CHECKER (spell_checker));
314 g_weak_ref_set (&dictionary->priv->spell_checker, spell_checker);
317 static void
318 spell_dictionary_set_property (GObject *object,
319 guint property_id,
320 const GValue *value,
321 GParamSpec *pspec)
323 switch (property_id) {
324 case PROP_SPELL_CHECKER:
325 spell_dictionary_set_spell_checker (
326 E_SPELL_DICTIONARY (object),
327 g_value_get_object (value));
328 return;
331 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
334 static void
335 spell_dictionary_get_property (GObject *object,
336 guint property_id,
337 GValue *value,
338 GParamSpec *pspec)
340 switch (property_id) {
341 case PROP_SPELL_CHECKER:
342 g_value_take_object (
343 value,
344 e_spell_dictionary_ref_spell_checker (
345 E_SPELL_DICTIONARY (object)));
346 return;
349 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
352 static void
353 spell_dictionary_dispose (GObject *object)
355 ESpellDictionaryPrivate *priv;
357 priv = E_SPELL_DICTIONARY_GET_PRIVATE (object);
359 g_weak_ref_set (&priv->spell_checker, NULL);
361 /* Chain up to parent's dispose() method. */
362 G_OBJECT_CLASS (e_spell_dictionary_parent_class)->dispose (object);
365 static void
366 spell_dictionary_finalize (GObject *object)
368 ESpellDictionaryPrivate *priv;
370 priv = E_SPELL_DICTIONARY_GET_PRIVATE (object);
372 g_free (priv->name);
373 g_free (priv->code);
374 g_free (priv->collate_key);
376 /* Chain up to parent's finalize() method. */
377 G_OBJECT_CLASS (e_spell_dictionary_parent_class)->finalize (object);
380 static void
381 e_spell_dictionary_class_init (ESpellDictionaryClass *class)
383 GObjectClass *object_class;
385 g_type_class_add_private (class, sizeof (ESpellDictionaryPrivate));
387 object_class = G_OBJECT_CLASS (class);
388 object_class->set_property = spell_dictionary_set_property;
389 object_class->get_property = spell_dictionary_get_property;
390 object_class->dispose = spell_dictionary_dispose;
391 object_class->finalize = spell_dictionary_finalize;
393 g_object_class_install_property (
394 object_class,
395 PROP_SPELL_CHECKER,
396 g_param_spec_object (
397 "spell-checker",
398 NULL,
399 "Parent spell checker",
400 E_TYPE_SPELL_CHECKER,
401 G_PARAM_READWRITE |
402 G_PARAM_CONSTRUCT_ONLY));
405 static void
406 e_spell_dictionary_init (ESpellDictionary *dictionary)
408 dictionary->priv = E_SPELL_DICTIONARY_GET_PRIVATE (dictionary);
410 if (!iso_639_table && !iso_3166_table) {
411 #if defined (ENABLE_NLS) && defined (HAVE_ISO_CODES)
412 bindtextdomain (ISO_639_DOMAIN, ISOCODESLOCALEDIR);
413 bind_textdomain_codeset (ISO_639_DOMAIN, "UTF-8");
415 bindtextdomain (ISO_3166_DOMAIN, ISOCODESLOCALEDIR);
416 bind_textdomain_codeset (ISO_3166_DOMAIN, "UTF-8");
417 #endif /* ENABLE_NLS && HAVE_ISO_CODES */
419 iso_639_table = g_hash_table_new_full (
420 (GHashFunc) g_str_hash,
421 (GEqualFunc) g_str_equal,
422 (GDestroyNotify) g_free,
423 (GDestroyNotify) g_free);
425 iso_3166_table = g_hash_table_new_full (
426 (GHashFunc) g_str_hash,
427 (GEqualFunc) g_str_equal,
428 (GDestroyNotify) g_free,
429 (GDestroyNotify) g_free);
431 #ifdef HAVE_ISO_CODES
432 iso_codes_parse (
433 &iso_639_parser, "iso_639.xml", iso_639_table);
434 iso_codes_parse (
435 &iso_3166_parser, "iso_3166.xml", iso_3166_table);
436 #endif /* HAVE_ISO_CODES */
440 ESpellDictionary *
441 e_spell_dictionary_new (ESpellChecker *spell_checker,
442 EnchantDict *enchant_dict)
444 ESpellDictionary *dictionary;
446 g_return_val_if_fail (E_IS_SPELL_CHECKER (spell_checker), NULL);
447 g_return_val_if_fail (enchant_dict != NULL, NULL);
449 dictionary = g_object_new (
450 E_TYPE_SPELL_DICTIONARY,
451 "spell-checker", spell_checker, NULL);
453 /* Since EnchantDict is not reference counted, ESpellChecker
454 * is loaning us the EnchantDict pointer. We do not own it. */
455 spell_dictionary_set_enchant_dict (dictionary, enchant_dict);
457 return dictionary;
460 ESpellDictionary *
461 e_spell_dictionary_new_bare (ESpellChecker *spell_checker,
462 const gchar *language_tag)
464 ESpellDictionary *dictionary;
465 struct _enchant_dict_description_data descr_data;
467 g_return_val_if_fail (E_IS_SPELL_CHECKER (spell_checker), NULL);
468 g_return_val_if_fail (language_tag != NULL, NULL);
470 dictionary = g_object_new (
471 E_TYPE_SPELL_DICTIONARY,
472 "spell-checker", spell_checker, NULL);
474 descr_data.language_tag = NULL;
475 descr_data.dict_name = NULL;
477 describe_dictionary (language_tag, NULL, NULL, NULL, &descr_data);
479 dictionary->priv->code = descr_data.language_tag;
480 dictionary->priv->name = descr_data.dict_name;
481 dictionary->priv->collate_key = g_utf8_collate_key (descr_data.dict_name, -1);
483 return dictionary;
487 * e_spell_dictionary_hash:
488 * @dictionary: an #ESpellDictionary
490 * Generates a hash value for @dictionary based on its ISO code.
491 * This function is intended for easily hashing an #ESpellDictionary
492 * to add to a #GHashTable or similar data structure.
494 * Returns: a hash value for @dictionary
496 guint
497 e_spell_dictionary_hash (ESpellDictionary *dictionary)
499 const gchar *code;
501 g_return_val_if_fail (E_IS_SPELL_DICTIONARY (dictionary), 0);
503 code = e_spell_dictionary_get_code (dictionary);
505 return g_str_hash (code);
509 * e_spell_dictionary_equal:
510 * @dictionary1: an #ESpellDictionary
511 * @dictionary2: another #ESpellDictionary
513 * Checks two #ESpellDictionary instances for equality based on their
514 * ISO codes.
516 * Returns: %TRUE if @dictionary1 and @dictionary2 are equal
518 gboolean
519 e_spell_dictionary_equal (ESpellDictionary *dictionary1,
520 ESpellDictionary *dictionary2)
522 const gchar *code1, *code2;
524 g_return_val_if_fail (E_IS_SPELL_DICTIONARY (dictionary1), FALSE);
525 g_return_val_if_fail (E_IS_SPELL_DICTIONARY (dictionary2), FALSE);
527 if (dictionary1 == dictionary2)
528 return TRUE;
530 code1 = e_spell_dictionary_get_code (dictionary1);
531 code2 = e_spell_dictionary_get_code (dictionary2);
533 return g_str_equal (code1, code2);
537 * e_spell_dictionary_compare:
538 * @dictionary1: an #ESpellDictionary
539 * @dictionary2: another #ESpellDictionary
541 * Compares @dictionary1 and @dictionary2 by their display names for
542 * the purpose of lexicographical sorting. Use this function where a
543 * #GCompareFunc callback is required, such as g_list_sort().
545 * Returns: 0 if the names match,
546 * a negative value if @dictionary1 < @dictionary2,
547 * or a positive value of @dictionary1 > @dictionary2
549 gint
550 e_spell_dictionary_compare (ESpellDictionary *dictionary1,
551 ESpellDictionary *dictionary2)
553 g_return_val_if_fail (E_IS_SPELL_DICTIONARY (dictionary1), 0);
554 g_return_val_if_fail (E_IS_SPELL_DICTIONARY (dictionary2), 0);
556 return strcmp (
557 dictionary1->priv->collate_key,
558 dictionary2->priv->collate_key);
562 * e_spell_dictionary_get_name:
563 * @dictionary: an #ESpellDictionary
565 * Returns the display name of the dictionary (for example
566 * "English (British)")
568 * Returns: the display name of the @dictionary
570 const gchar *
571 e_spell_dictionary_get_name (ESpellDictionary *dictionary)
573 g_return_val_if_fail (E_IS_SPELL_DICTIONARY (dictionary), NULL);
575 return dictionary->priv->name;
579 * e_spell_dictionary_get_code:
580 * @dictionary: an #ESpellDictionary
582 * Returns the ISO code of the spell-checking language for
583 * @dictionary (for example "en_US").
585 * Returns: the language code of the @dictionary
587 const gchar *
588 e_spell_dictionary_get_code (ESpellDictionary *dictionary)
590 g_return_val_if_fail (E_IS_SPELL_DICTIONARY (dictionary), NULL);
592 return dictionary->priv->code;
596 * e_spell_dictionary_ref_spell_checker:
597 * @dictionary: an #ESpellDictionary
599 * Returns a new reference to the #ESpellChecker which owns the dictionary.
600 * Unreference the #ESpellChecker with g_object_unref() when finished with it.
602 * Returns: an #ESpellChecker
604 ESpellChecker *
605 e_spell_dictionary_ref_spell_checker (ESpellDictionary *dictionary)
607 g_return_val_if_fail (E_IS_SPELL_DICTIONARY (dictionary), NULL);
609 return g_weak_ref_get (&dictionary->priv->spell_checker);
613 * e_spell_dictionary_check_word:
614 * @dictionary: an #ESpellDictionary
615 * @word: a word to spell-check
616 * @length: length of @word in bytes or -1 when %NULL-terminated
618 * Tries to lookup the @word in the @dictionary to check whether
619 * it's spelled correctly or not.
621 * Returns: %TRUE if @word is recognized, %FALSE otherwise
623 gboolean
624 e_spell_dictionary_check_word (ESpellDictionary *dictionary,
625 const gchar *word,
626 gsize length)
628 ESpellChecker *spell_checker;
629 EnchantDict *enchant_dict;
630 gboolean recognized;
632 g_return_val_if_fail (E_IS_SPELL_DICTIONARY (dictionary), TRUE);
633 g_return_val_if_fail (word != NULL && *word != '\0', TRUE);
635 spell_checker = e_spell_dictionary_ref_spell_checker (dictionary);
636 g_return_val_if_fail (spell_checker != NULL, TRUE);
638 enchant_dict = e_spell_checker_get_enchant_dict (
639 spell_checker, e_spell_dictionary_get_code (dictionary));
640 g_return_val_if_fail (enchant_dict != NULL, TRUE);
642 recognized = (enchant_dict_check (enchant_dict, word, length) == 0);
644 g_object_unref (spell_checker);
646 return recognized;
650 * e_spell_dictionary_learn_word:
651 * @dictionary: an #ESpellDictionary
652 * @word: a word to add to @dictionary
653 * @length: length of @word in bytes or -1 when %NULL-terminated
655 * Permanently adds @word to @dictionary so that next time calling
656 * e_spell_dictionary_check() on the @word will return %TRUE.
658 void
659 e_spell_dictionary_learn_word (ESpellDictionary *dictionary,
660 const gchar *word,
661 gsize length)
663 ESpellChecker *spell_checker;
664 EnchantDict *enchant_dict;
666 g_return_if_fail (E_IS_SPELL_DICTIONARY (dictionary));
667 g_return_if_fail (word != NULL && *word != '\0');
669 spell_checker = e_spell_dictionary_ref_spell_checker (dictionary);
670 g_return_if_fail (spell_checker != NULL);
672 enchant_dict = e_spell_checker_get_enchant_dict (
673 spell_checker, e_spell_dictionary_get_code (dictionary));
674 g_return_if_fail (enchant_dict != NULL);
676 enchant_dict_add_to_personal (enchant_dict, word, length);
678 g_object_unref (spell_checker);
682 * e_spell_dictionary_ignore_word:
683 * @dictionary: an #ESpellDictionary
684 * @word: a word to add to ignore list
685 * @length: length of @word in bytes or -1 when %NULL-terminated
687 * Adds @word to temporary ignore list of the @dictionary, so that
688 * e_spell_dictionary_check() on the @word will return %TRUE. The
689 * list is cleared when the dictionary is freed.
691 void
692 e_spell_dictionary_ignore_word (ESpellDictionary *dictionary,
693 const gchar *word,
694 gsize length)
696 ESpellChecker *spell_checker;
697 EnchantDict *enchant_dict;
699 g_return_if_fail (E_IS_SPELL_DICTIONARY (dictionary));
700 g_return_if_fail (word != NULL && *word != '\0');
702 spell_checker = e_spell_dictionary_ref_spell_checker (dictionary);
703 g_return_if_fail (spell_checker != NULL);
705 enchant_dict = e_spell_checker_get_enchant_dict (
706 spell_checker, e_spell_dictionary_get_code (dictionary));
707 g_return_if_fail (enchant_dict != NULL);
709 enchant_dict_add_to_session (enchant_dict, word, length);
711 g_object_unref (spell_checker);
715 * e_spell_dictionary_get_suggestions:
716 * @dictionary: an #ESpellDictionary
717 * @word: a word to which to find suggestions
718 * @length: length of @word in bytes or -1 when %NULL-terminated
720 * Provides list of alternative spellings of @word.
722 * Free the returned spelling suggestions with g_free(), and the list
723 * itself with g_list_free(). An easy way to free the list properly in
724 * one step is as follows:
726 * |[
727 * g_list_free_full (list, (GDestroyNotify) g_free);
728 * ]|
730 * Returns: a list of spelling suggestions for @word
732 GList *
733 e_spell_dictionary_get_suggestions (ESpellDictionary *dictionary,
734 const gchar *word,
735 gsize length)
737 ESpellChecker *spell_checker;
738 EnchantDict *enchant_dict;
739 GList *list = NULL;
740 gchar **suggestions;
741 gsize ii, count = 0;
743 g_return_val_if_fail (E_IS_SPELL_DICTIONARY (dictionary), NULL);
744 g_return_val_if_fail (word != NULL && *word != '\0', NULL);
746 spell_checker = e_spell_dictionary_ref_spell_checker (dictionary);
747 g_return_val_if_fail (spell_checker != NULL, NULL);
749 enchant_dict = e_spell_checker_get_enchant_dict (
750 spell_checker, e_spell_dictionary_get_code (dictionary));
751 g_return_val_if_fail (enchant_dict != NULL, NULL);
753 suggestions = enchant_dict_suggest (enchant_dict, word, length, &count);
754 for (ii = 0; ii < count; ii++)
755 list = g_list_prepend (list, g_strdup (suggestions[ii]));
756 enchant_dict_free_suggestions (enchant_dict, suggestions);
758 g_object_unref (spell_checker);
760 return g_list_reverse (list);
764 * e_spell_dictionary_add_correction
765 * @dictionary: an #ESpellDictionary
766 * @misspelled: a misspelled word
767 * @misspelled_length: length of @misspelled in bytes or -1 when
768 * %NULL-terminated
769 * @correction: the corrected word
770 * @correction_length: length of @correction in bytes or -1 when
771 * %NULL-terminated
773 * Learns a new @correction of @misspelled word.
775 void
776 e_spell_dictionary_store_correction (ESpellDictionary *dictionary,
777 const gchar *misspelled,
778 gsize misspelled_length,
779 const gchar *correction,
780 gsize correction_length)
782 ESpellChecker *spell_checker;
783 EnchantDict *enchant_dict;
785 g_return_if_fail (E_IS_SPELL_DICTIONARY (dictionary));
786 g_return_if_fail (misspelled != NULL && *misspelled != '\0');
787 g_return_if_fail (correction != NULL && *correction != '\0');
789 spell_checker = e_spell_dictionary_ref_spell_checker (dictionary);
790 g_return_if_fail (spell_checker != NULL);
792 enchant_dict = e_spell_checker_get_enchant_dict (
793 spell_checker, e_spell_dictionary_get_code (dictionary));
794 g_return_if_fail (enchant_dict != NULL);
796 enchant_dict_store_replacement (
797 enchant_dict,
798 misspelled, misspelled_length,
799 correction, correction_length);
801 g_object_unref (spell_checker);