spell checker support for multiple languages

This commit is contained in:
berkeviktor@aol.com 2011-08-07 13:41:43 +02:00
parent 19b7e2f062
commit 08e5778b19
12 changed files with 4379 additions and 22 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,7 @@
#define USE_GMODULE
#define USE_PLUGIN
#define USE_LIBSEXY
#define HAVE_ISO_CODES
#define PACKAGE_NAME "xchat"
#define PACKAGE_VERSION "1496-4"
#define XCHAT_RELEASE "2.8.8"

View File

@ -19,3 +19,4 @@ http://ftp.gnome.org/pub/gnome/binaries/win64/pango/1.28/pango-dev_1.28.3-1_win6
http://xchat-wdk.googlecode.com/files/Enchant-WDK%201.6.0-2%20x64.7z
http://xchat-wdk.googlecode.com/files/Lua-WDK%205.1.4-2-2%20x64.7z
http://xchat-wdk.googlecode.com/files/OpenSSL-WDK%201.0.0d%20x64.7z
http://xchat-wdk.googlecode.com/files/LibXML-WDK%202.7.8%20x64.7z

View File

@ -21,3 +21,4 @@ http://xchat-wdk.googlecode.com/files/Lua-WDK%205.1.4-2-2%20x86.7z
http://xchat-wdk.googlecode.com/files/OpenSSL-WDK%201.0.0d%20x86.7z
http://xchat-wdk.googlecode.com/files/myspell-20101001.7z
http://xchat-wdk.googlecode.com/files/gettext-tools-0.17-msgfmt.zip
http://xchat-wdk.googlecode.com/files/LibXML-WDK%202.7.8%20x86.7z

View File

@ -25,6 +25,8 @@ rawlog.obj \
search.obj \
servlistgui.obj \
setup.obj \
sexy-iso-codes.obj \
sexy-marshal.obj \
sexy-spell-entry.obj \
textgui.obj \
urlgrab.obj \

301
src/fe-gtk/sexy-iso-codes.c Normal file
View File

@ -0,0 +1,301 @@
/*
* Copyright (C) 2005 Nathan Fredrickson
* Borrowed from Galeon, renamed, and simplified to only use iso-codes with no
* fallback method.
*
* Copyright (C) 2004 Christian Persch
* Copyright (C) 2004 Crispin Flowerday
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "../../config.h"
#include "sexy-iso-codes.h"
#include <glib/gi18n.h>
#include <string.h>
#include <libxml/xmlreader.h>
static GHashTable *iso_639_table = NULL;
static GHashTable *iso_3166_table = NULL;
#define ISO_639_DOMAIN "iso_639"
#define ISO_3166_DOMAIN "iso_3166"
#ifdef HAVE_ISO_CODES
#define ISOCODESLOCALEDIR "/share/locale"
static void
read_iso_639_entry (xmlTextReaderPtr reader,
GHashTable *table)
{
xmlChar *code, *name;
code = xmlTextReaderGetAttribute (reader, (const xmlChar *) "iso_639_1_code");
name = xmlTextReaderGetAttribute (reader, (const xmlChar *) "name");
/* Get iso-639-2 code */
if (code == NULL || code[0] == '\0')
{
xmlFree (code);
/* FIXME: use the 2T or 2B code? */
code = xmlTextReaderGetAttribute (reader, (const xmlChar *) "iso_639_2T_code");
}
if (code != NULL && code[0] != '\0' && name != NULL && name[0] != '\0')
{
g_hash_table_insert (table, code, name);
}
else
{
xmlFree (code);
xmlFree (name);
}
}
static void
read_iso_3166_entry (xmlTextReaderPtr reader,
GHashTable *table)
{
xmlChar *code, *name;
code = xmlTextReaderGetAttribute (reader, (const xmlChar *) "alpha_2_code");
name = xmlTextReaderGetAttribute (reader, (const xmlChar *) "name");
if (code != NULL && code[0] != '\0' && name != NULL && name[0] != '\0')
{
char *lcode;
lcode = g_ascii_strdown ((char *) code, -1);
xmlFree (code);
g_hash_table_insert (table, lcode, name);
}
else
{
xmlFree (code);
xmlFree (name);
}
}
typedef enum
{
STATE_START,
STATE_STOP,
STATE_ENTRIES,
} ParserState;
static gboolean
load_iso_entries (int iso,
GFunc read_entry_func,
gpointer user_data)
{
xmlTextReaderPtr reader;
ParserState state = STATE_START;
xmlChar iso_entries[32], iso_entry[32];
char *filename;
int ret = -1;
filename = g_strdup_printf (".\\share\\xml\\iso-codes\\iso_%d.xml", iso);
reader = xmlNewTextReaderFilename (filename);
if (reader == NULL) goto out;
xmlStrPrintf (iso_entries, sizeof (iso_entries),
(xmlChar *)"iso_%d_entries", iso);
xmlStrPrintf (iso_entry, sizeof (iso_entry),
(xmlChar *)"iso_%d_entry", iso);
ret = xmlTextReaderRead (reader);
while (ret == 1)
{
const xmlChar *tag;
xmlReaderTypes type;
tag = xmlTextReaderConstName (reader);
type = xmlTextReaderNodeType (reader);
if (state == STATE_ENTRIES &&
type == XML_READER_TYPE_ELEMENT &&
xmlStrEqual (tag, iso_entry))
{
read_entry_func (reader, user_data);
}
else if (state == STATE_START &&
type == XML_READER_TYPE_ELEMENT &&
xmlStrEqual (tag, iso_entries))
{
state = STATE_ENTRIES;
}
else if (state == STATE_ENTRIES &&
type == XML_READER_TYPE_END_ELEMENT &&
xmlStrEqual (tag, iso_entries))
{
state = STATE_STOP;
}
else if (type == XML_READER_TYPE_SIGNIFICANT_WHITESPACE ||
type == XML_READER_TYPE_WHITESPACE ||
type == XML_READER_TYPE_TEXT ||
type == XML_READER_TYPE_COMMENT)
{
/* eat it */
}
else
{
/* ignore it */
}
ret = xmlTextReaderRead (reader);
}
xmlFreeTextReader (reader);
out:
if (ret < 0 || state != STATE_STOP)
{
/* This is not critical, we will fallback to our own code */
g_free (filename);
return FALSE;
}
g_free (filename);
return TRUE;
}
#endif /* HAVE_ISO_CODES */
static void
ensure_iso_codes_initialised (void)
{
static gboolean initialised = FALSE;
if (initialised == TRUE)
{
return;
}
initialised = TRUE;
#if defined (ENABLE_NLS) && defined (HAVE_ISO_CODES)
bindtextdomain (ISO_639_DOMAIN, ISOCODESLOCALEDIR);
bind_textdomain_codeset (ISO_639_DOMAIN, "UTF-8");
bindtextdomain(ISO_3166_DOMAIN, ISOCODESLOCALEDIR);
bind_textdomain_codeset (ISO_3166_DOMAIN, "UTF-8");
#endif
iso_639_table = g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify) xmlFree,
(GDestroyNotify) xmlFree);
iso_3166_table = g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify) g_free,
(GDestroyNotify) xmlFree);
#ifdef HAVE_ISO_CODES
load_iso_entries (639, (GFunc) read_iso_639_entry, iso_639_table);
load_iso_entries (3166, (GFunc) read_iso_3166_entry, iso_3166_table);
#endif
}
static char *
get_iso_name_for_lang_code (const char *code)
{
char **str;
char *name = NULL;
const char *langname, *localename;
int len;
str = g_strsplit (code, "_", -1);
/* count the entries */
for (len = 0; str[len]; len++ ) /* empty */;
g_return_val_if_fail (len != 0, NULL);
langname = (const char *) g_hash_table_lookup (iso_639_table, str[0]);
if (len == 1 && langname != NULL)
{
name = g_strdup (dgettext (ISO_639_DOMAIN, langname));
}
else if (len == 2 && langname != NULL)
{
localename = (const char *) g_hash_table_lookup (iso_3166_table, str[1]);
if (localename != NULL)
{
/* translators: the first %s is the language name, and the
* second %s is the locale name. Example:
* "French (France)
*
* Also: The text before the "|" is context to help you decide on
* the correct translation. You MUST OMIT it in the translated string.
*/
name = g_strdup_printf (Q_("language|%s (%s)"),
dgettext (ISO_639_DOMAIN, langname),
dgettext (ISO_3166_DOMAIN, localename));
}
else
{
name = g_strdup_printf (Q_("language|%s (%s)"),
dgettext (ISO_639_DOMAIN, langname), str[1]);
}
}
g_strfreev (str);
return name;
}
/**
* gtkspell_iso_codes_lookup_name_for_code:
* @code: A language code, e.g. en_CA
*
* Looks up a name to display to the user for a language code,
* this might use the iso-codes package if support was compiled
* in, and it is available
*
* Returns: the UTF-8 string to display to the user, or NULL if
* a name for the code could not be found
*/
char *
gtkspell_iso_codes_lookup_name_for_code (const char *code)
{
char * lcode;
char * ret;
g_return_val_if_fail (code != NULL, NULL);
ensure_iso_codes_initialised ();
lcode = g_ascii_strdown (code, -1);
ret = get_iso_name_for_lang_code (lcode);
g_free (lcode);
return ret;
}

View File

@ -0,0 +1,37 @@
/*
* Copyright (C) 2005 Nathan Fredrickson
* Borrowed from Galeon, renamed, and simplified to only use iso-codes with no
* fallback method.
*
* Copyright (C) 2004 Christian Persch
* Copyright (C) 2004 Crispin Flowerday
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#ifndef GTKSPELL_ISO_CODES_H
#define GTKSPELL_ISO_CODES_H
#include <glib.h>
G_BEGIN_DECLS
char * gtkspell_iso_codes_lookup_name_for_code (const char *code);
G_END_DECLS
#endif

129
src/fe-gtk/sexy-marshal.c Normal file
View File

@ -0,0 +1,129 @@
#include <glib-object.h>
#ifdef G_ENABLE_DEBUG
#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v)
#define g_marshal_value_peek_char(v) g_value_get_char (v)
#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v)
#define g_marshal_value_peek_int(v) g_value_get_int (v)
#define g_marshal_value_peek_uint(v) g_value_get_uint (v)
#define g_marshal_value_peek_long(v) g_value_get_long (v)
#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v)
#define g_marshal_value_peek_int64(v) g_value_get_int64 (v)
#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v)
#define g_marshal_value_peek_enum(v) g_value_get_enum (v)
#define g_marshal_value_peek_flags(v) g_value_get_flags (v)
#define g_marshal_value_peek_float(v) g_value_get_float (v)
#define g_marshal_value_peek_double(v) g_value_get_double (v)
#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v)
#define g_marshal_value_peek_param(v) g_value_get_param (v)
#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v)
#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v)
#define g_marshal_value_peek_object(v) g_value_get_object (v)
#else /* !G_ENABLE_DEBUG */
/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.
* Do not access GValues directly in your code. Instead, use the
* g_value_get_*() functions
*/
#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int
#define g_marshal_value_peek_char(v) (v)->data[0].v_int
#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint
#define g_marshal_value_peek_int(v) (v)->data[0].v_int
#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint
#define g_marshal_value_peek_long(v) (v)->data[0].v_long
#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong
#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64
#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64
#define g_marshal_value_peek_enum(v) (v)->data[0].v_long
#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong
#define g_marshal_value_peek_float(v) (v)->data[0].v_float
#define g_marshal_value_peek_double(v) (v)->data[0].v_double
#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer
#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer
#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer
#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer
#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer
#endif /* !G_ENABLE_DEBUG */
/* BOOLEAN:STRING (./marshal.list:1) */
void
sexy_marshal_BOOLEAN__STRING (GClosure *closure,
GValue *return_value,
guint n_param_values,
const GValue *param_values,
gpointer invocation_hint,
gpointer marshal_data)
{
typedef gboolean (*GMarshalFunc_BOOLEAN__STRING) (gpointer data1,
gpointer arg_1,
gpointer data2);
register GMarshalFunc_BOOLEAN__STRING callback;
register GCClosure *cc = (GCClosure*) closure;
register gpointer data1, data2;
gboolean v_return;
g_return_if_fail (return_value != NULL);
g_return_if_fail (n_param_values == 2);
if (G_CCLOSURE_SWAP_DATA (closure))
{
data1 = closure->data;
data2 = g_value_peek_pointer (param_values + 0);
}
else
{
data1 = g_value_peek_pointer (param_values + 0);
data2 = closure->data;
}
callback = (GMarshalFunc_BOOLEAN__STRING) (marshal_data ? marshal_data : cc->callback);
v_return = callback (data1,
g_marshal_value_peek_string (param_values + 1),
data2);
g_value_set_boolean (return_value, v_return);
}
/* OBJECT:OBJECT,OBJECT (./marshal.list:2) */
void
sexy_marshal_OBJECT__OBJECT_OBJECT (GClosure *closure,
GValue *return_value,
guint n_param_values,
const GValue *param_values,
gpointer invocation_hint,
gpointer marshal_data)
{
typedef GObject* (*GMarshalFunc_OBJECT__OBJECT_OBJECT) (gpointer data1,
gpointer arg_1,
gpointer arg_2,
gpointer data2);
register GMarshalFunc_OBJECT__OBJECT_OBJECT callback;
register GCClosure *cc = (GCClosure*) closure;
register gpointer data1, data2;
GObject* v_return;
g_return_if_fail (return_value != NULL);
g_return_if_fail (n_param_values == 3);
if (G_CCLOSURE_SWAP_DATA (closure))
{
data1 = closure->data;
data2 = g_value_peek_pointer (param_values + 0);
}
else
{
data1 = g_value_peek_pointer (param_values + 0);
data2 = closure->data;
}
callback = (GMarshalFunc_OBJECT__OBJECT_OBJECT) (marshal_data ? marshal_data : cc->callback);
v_return = callback (data1,
g_marshal_value_peek_object (param_values + 1),
g_marshal_value_peek_object (param_values + 2),
data2);
g_value_take_object (return_value, v_return);
}

28
src/fe-gtk/sexy-marshal.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef __sexy_marshal_MARSHAL_H__
#define __sexy_marshal_MARSHAL_H__
#include <glib-object.h>
G_BEGIN_DECLS
/* BOOLEAN:STRING (./marshal.list:1) */
extern void sexy_marshal_BOOLEAN__STRING (GClosure *closure,
GValue *return_value,
guint n_param_values,
const GValue *param_values,
gpointer invocation_hint,
gpointer marshal_data);
/* OBJECT:OBJECT,OBJECT (./marshal.list:2) */
extern void sexy_marshal_OBJECT__OBJECT_OBJECT (GClosure *closure,
GValue *return_value,
guint n_param_values,
const GValue *param_values,
gpointer invocation_hint,
gpointer marshal_data);
G_END_DECLS
#endif /* __sexy_marshal_MARSHAL_H__ */

View File

@ -30,8 +30,8 @@
#include <glib/gi18n.h>
#include <sys/types.h>
#include <sys/stat.h>
/*#include "gtkspell-iso-codes.h"
#include "sexy-marshal.h"*/
#include "sexy-iso-codes.h"
#include "sexy-marshal.h"
#include "typedef.h"
@ -211,14 +211,14 @@ sexy_spell_entry_class_init(SexySpellEntryClass *klass)
* Returns: %FALSE to indicate that the word should be marked as
* correct.
*/
/* signals[WORD_CHECK] = g_signal_new("word_check",
signals[WORD_CHECK] = g_signal_new("word_check",
G_TYPE_FROM_CLASS(object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(SexySpellEntryClass, word_check),
(GSignalAccumulator) spell_accumulator, NULL,
sexy_marshal_BOOLEAN__STRING,
G_TYPE_BOOLEAN,
1, G_TYPE_STRING);*/
1, G_TYPE_STRING);
}
static void
@ -495,10 +495,6 @@ build_spelling_menu(SexySpellEntry *entry, const gchar *word)
if (entry->priv->dict_list == NULL)
return topmenu;
#if 1
dict = (struct EnchantDict *) entry->priv->dict_list->data;
build_suggestion_menu(entry, topmenu, dict, word);
#else
/* Suggestions */
if (g_slist_length(entry->priv->dict_list) == 1) {
dict = (struct EnchantDict *) entry->priv->dict_list->data;
@ -527,7 +523,6 @@ build_spelling_menu(SexySpellEntry *entry, const gchar *word)
build_suggestion_menu(entry, menu, dict, word);
}
}
#endif
/* Separator */
mi = gtk_separator_menu_item_new ();
@ -541,11 +536,6 @@ build_spelling_menu(SexySpellEntry *entry, const gchar *word)
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mi), gtk_image_new_from_stock(GTK_STOCK_ADD, GTK_ICON_SIZE_MENU));
#if 1
dict = (struct EnchantDict *) entry->priv->dict_list->data;
g_object_set_data(G_OBJECT(mi), "enchant-dict", dict);
g_signal_connect(G_OBJECT(mi), "activate", G_CALLBACK(add_to_dictionary), entry);
#else
if (g_slist_length(entry->priv->dict_list) == 1) {
dict = (struct EnchantDict *) entry->priv->dict_list->data;
g_object_set_data(G_OBJECT(mi), "enchant-dict", dict);
@ -577,7 +567,6 @@ build_spelling_menu(SexySpellEntry *entry, const gchar *word)
gtk_menu_shell_append(GTK_MENU_SHELL(menu), submi);
}
}
#endif
gtk_widget_show_all(mi);
gtk_menu_shell_append(GTK_MENU_SHELL(topmenu), mi);
@ -759,11 +748,7 @@ word_misspelled(SexySpellEntry *entry, int start, int end)
g_strlcpy(word, text + start, end - start + 1);
#if 0
g_signal_emit(entry, signals[WORD_CHECK], 0, word, &ret);
#else
ret = default_word_check (entry, word);
#endif
g_free(word);
return ret;
@ -1121,8 +1106,8 @@ gchar *
sexy_spell_entry_get_language_name(const SexySpellEntry *entry,
const gchar *lang)
{
/*if (have_enchant)
return gtkspell_iso_codes_lookup_name_for_code(lang);*/
if (have_enchant)
return gtkspell_iso_codes_lookup_name_for_code(lang);
return NULL;
}

View File

@ -9,7 +9,7 @@ LIBS = $(LIBS) gdi32.lib shell32.lib user32.lib advapi32.lib imm32.lib ole32.lib
GLIB = /I$(DEV)\include\glib-2.0 /I$(DEV)\lib\glib-2.0\include
GTK = /I$(DEV)\include\gtk-2.0 /I$(DEV)\lib\gtk-2.0\include /I$(DEV)\include\atk-1.0 /I$(DEV)\include\cairo /I$(DEV)\include\pango-1.0 /I$(DEV)\include\gdk-pixbuf-2.0
LIBS = $(LIBS) /libpath:$(DEV)\lib gtk-win32-2.0.lib gdk-win32-2.0.lib atk-1.0.lib gio-2.0.lib gdk_pixbuf-2.0.lib pangowin32-1.0.lib pangocairo-1.0.lib pango-1.0.lib cairo.lib gobject-2.0.lib gmodule-2.0.lib glib-2.0.lib intl.lib
LIBS = $(LIBS) /libpath:$(DEV)\lib gtk-win32-2.0.lib gdk-win32-2.0.lib atk-1.0.lib gio-2.0.lib gdk_pixbuf-2.0.lib pangowin32-1.0.lib pangocairo-1.0.lib pango-1.0.lib cairo.lib gobject-2.0.lib gmodule-2.0.lib glib-2.0.lib intl.lib libxml2.lib
LUALIB = lua51
LUAOUTPUT = xclua.dll