[gspell/wip/icu: 1/5] icu: implement get_language_name_from_code()




commit 5dec44989801bab9aef8093d6e0e8b410018b8d1
Author: Sébastien Wilmet <swilmet gnome org>
Date:   Wed Sep 30 00:56:34 2020 +0200

    icu: implement get_language_name_from_code()
    
    Some functions are copied from Tepl. But use the Gspell namespace, to
    avoid potential symbol clashes on certain platforms (see also the
    comment in update-sourceregion.sh).
    
    https://gitlab.gnome.org/GNOME/gspell/-/issues/14

 README                     |   1 +
 configure.ac               |   2 +-
 docs/reference/Makefile.am |   1 +
 gspell/Makefile.am         |   2 +
 gspell/gspell-icu.c        | 229 +++++++++++++++++++++++++++++++++++++++++++++
 gspell/gspell-icu.h        |  58 ++++++++++++
 po/POTFILES.in             |   1 +
 testsuite/Makefile.am      |   3 +
 testsuite/test-icu.c       |  49 ++++++++++
 9 files changed, 345 insertions(+), 1 deletion(-)
---
diff --git a/README b/README
index e39b98a..1d98258 100644
--- a/README
+++ b/README
@@ -28,6 +28,7 @@ Dependencies
 * GTK >= 3.20
 * Enchant >= 2.1.3
 * iso-codes
+* ICU - http://site.icu-project.org/
 
 Notes for packagers
 -------------------
diff --git a/configure.ac b/configure.ac
index 4141157..5d87a1f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -91,7 +91,7 @@ AX_COMPILER_FLAGS([WARN_CFLAGS], [WARN_LDFLAGS], [yes])
 AX_REQUIRE_DEFINED([AX_PKG_CHECK_MODULES])
 AX_PKG_CHECK_MODULES([DEP],
                     [glib-2.0 >= $glib_req  gtk+-3.0 >= $gtk_req  enchant-2 >= $enchant_req],
-                    [])
+                    [icu-uc])
 
 # iso-codes
 AX_REQUIRE_DEFINED([PKG_CHECK_EXISTS])
diff --git a/docs/reference/Makefile.am b/docs/reference/Makefile.am
index d9c2fd2..b5fa4e8 100644
--- a/docs/reference/Makefile.am
+++ b/docs/reference/Makefile.am
@@ -36,6 +36,7 @@ IGNORE_HFILES =                                       \
        gspell-current-word-policy.h            \
        gspell-entry-private.h                  \
        gspell-entry-utils.h                    \
+       gspell-icu.h                            \
        gspell-init.h                           \
        gspell-inline-checker-text-buffer.h     \
        gspell-osx.h                            \
diff --git a/gspell/Makefile.am b/gspell/Makefile.am
index c4e15a4..d12a551 100644
--- a/gspell/Makefile.am
+++ b/gspell/Makefile.am
@@ -53,6 +53,7 @@ gspell_private_headers =                      \
        gspell-current-word-policy.h            \
        gspell-entry-private.h                  \
        gspell-entry-utils.h                    \
+       gspell-icu.h                            \
        gspell-init.h                           \
        gspell-inline-checker-text-buffer.h     \
        gspell-text-iter.h                      \
@@ -63,6 +64,7 @@ gspell_private_c_files =                      \
        gspell-context-menu.c                   \
        gspell-current-word-policy.c            \
        gspell-entry-utils.c                    \
+       gspell-icu.c                            \
        gspell-init.c                           \
        gspell-inline-checker-text-buffer.c     \
        gspell-text-iter.c                      \
diff --git a/gspell/gspell-icu.c b/gspell/gspell-icu.c
new file mode 100644
index 0000000..e915c5f
--- /dev/null
+++ b/gspell/gspell-icu.c
@@ -0,0 +1,229 @@
+/*
+ * This file is part of gspell, a spell-checking library.
+ *
+ * Copyright 2020 - Sébastien Wilmet <swilmet gnome org>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "gspell-icu.h"
+#include <unicode/uloc.h>
+
+/* Some of these functions are copied from the Tepl library. */
+
+/* Wrapper around u_strToUTF8() that handles the pre-flighting.
+ *
+ * Returns: (transfer full) (nullable): the newly-allocated string with the
+ * right size. Free with g_free() when no longer needed.
+ */
+char *
+_gspell_icu_strToUTF8 (int32_t     *pDestLength,
+                      const UChar *src,
+                      int32_t      srcLength,
+                      UErrorCode  *pErrorCode)
+{
+       int32_t my_DestLength = 0;
+       UErrorCode my_ErrorCode = U_ZERO_ERROR;
+       char *dest = NULL;
+
+       u_strToUTF8 (NULL, 0, &my_DestLength,
+                    src, srcLength,
+                    &my_ErrorCode);
+
+       if (my_ErrorCode != U_BUFFER_OVERFLOW_ERROR &&
+           my_ErrorCode != U_STRING_NOT_TERMINATED_WARNING)
+       {
+               if (pDestLength != NULL)
+               {
+                       *pDestLength = my_DestLength;
+               }
+               if (pErrorCode != NULL)
+               {
+                       *pErrorCode = my_ErrorCode;
+               }
+
+               return NULL;
+       }
+
+       dest = g_malloc0 (my_DestLength + 1);
+
+       u_strToUTF8 (dest, my_DestLength + 1, pDestLength,
+                    src, srcLength,
+                    pErrorCode);
+
+       return dest;
+}
+
+/* Returns: (transfer full) (nullable): a nul-terminated UTF-8 string. Free with
+ * g_free() when no longer needed.
+ */
+char *
+_gspell_icu_strToUTF8Simple (const UChar *uchars)
+{
+       char *utf8_str;
+       UErrorCode error_code = U_ZERO_ERROR;
+
+       utf8_str = _gspell_icu_strToUTF8 (NULL, uchars, -1, &error_code);
+
+       if (U_FAILURE (error_code))
+       {
+               g_free (utf8_str);
+               return NULL;
+       }
+
+       return utf8_str;
+}
+
+/* Wrapper around uloc_getDisplayName() that handles the pre-flighting.
+ *
+ * Returns: (transfer full) (nullable): the result as a newly-allocated buffer
+ * with the right size. Free with g_free() when no longer needed.
+ */
+UChar *
+_gspell_icu_loc_getDisplayName (const char *localeID,
+                               const char *inLocaleID,
+                               UErrorCode *err)
+{
+       UChar *result = NULL;
+       int32_t result_size;
+       UErrorCode my_err = U_ZERO_ERROR;
+
+       result_size = uloc_getDisplayName (localeID,
+                                          inLocaleID,
+                                          NULL, 0,
+                                          &my_err);
+
+       if (my_err != U_BUFFER_OVERFLOW_ERROR &&
+           my_err != U_STRING_NOT_TERMINATED_WARNING)
+       {
+               if (err != NULL)
+               {
+                       *err = my_err;
+               }
+
+               return NULL;
+       }
+
+       result = g_new0 (UChar, result_size + 1);
+
+       uloc_getDisplayName (localeID,
+                            inLocaleID,
+                            result, result_size + 1,
+                            err);
+
+       return result;
+}
+
+/* Returns: (transfer full) (nullable): the result as a UTF-8 string. Free with
+ * g_free() when no longer needed.
+ */
+char *
+_gspell_icu_loc_getDisplayNameSimple (const char *localeID,
+                                     const char *inLocaleID)
+{
+       UChar *result;
+       char *utf8_result;
+       UErrorCode err = U_ZERO_ERROR;
+
+       result = _gspell_icu_loc_getDisplayName (localeID, inLocaleID, &err);
+
+       if (U_FAILURE (err))
+       {
+               g_free (result);
+               return NULL;
+       }
+
+       utf8_result = _gspell_icu_strToUTF8Simple (result);
+       g_free (result);
+       return utf8_result;
+}
+
+/* Wrapper around uloc_canonicalize() that handles the pre-flighting.
+ *
+ * Returns: (transfer full) (nullable): the result as a newly-allocated buffer
+ * with the right size. Free with g_free() when no longer needed.
+ */
+char *
+_gspell_icu_loc_canonicalize (const char *localeID,
+                             UErrorCode *err)
+{
+       char *result = NULL;
+       int32_t result_size;
+       UErrorCode my_err = U_ZERO_ERROR;
+
+       result_size = uloc_canonicalize (localeID, NULL, 0, &my_err);
+
+       if (my_err != U_BUFFER_OVERFLOW_ERROR &&
+           my_err != U_STRING_NOT_TERMINATED_WARNING)
+       {
+               if (err != NULL)
+               {
+                       *err = my_err;
+               }
+
+               return NULL;
+       }
+
+       result = g_new0 (char, result_size + 1);
+       uloc_canonicalize (localeID, result, result_size + 1, err);
+       return result;
+}
+
+/* Returns: (transfer full) (nullable): the result, or %NULL in case of error.
+ * Free with g_free() when no longer needed.
+ */
+char *
+_gspell_icu_loc_canonicalizeSimple (const char *localeID)
+{
+       char *result;
+       UErrorCode err = U_ZERO_ERROR;
+
+       result = _gspell_icu_loc_canonicalize (localeID, &err);
+
+       if (U_FAILURE (err))
+       {
+               g_free (result);
+               return NULL;
+       }
+
+       return result;
+}
+
+/* This function uses gspell's terminology:
+ * "Language code": as in gspell_language_get_code().
+ * "Language name": as in gspell_language_get_name().
+ *
+ * Returns: (transfer full) (nullable): the language name, or %NULL in case of
+ * error. Free with g_free() when no longer needed.
+ */
+char *
+_gspell_icu_get_language_name_from_code (const char *language_code)
+{
+       char *canonicalized_language_code;
+       char *language_name;
+
+       /* language_code can come from an outside/foreign source, so it's better
+        * to pass it through level 2 canonicalization.
+        */
+       canonicalized_language_code = _gspell_icu_loc_canonicalizeSimple (language_code);
+       if (canonicalized_language_code == NULL)
+       {
+               return NULL;
+       }
+
+       /* NULL: for the default locale. */
+       language_name = _gspell_icu_loc_getDisplayNameSimple (canonicalized_language_code, NULL);
+       g_free (canonicalized_language_code);
+       return language_name;
+}
diff --git a/gspell/gspell-icu.h b/gspell/gspell-icu.h
new file mode 100644
index 0000000..381fa33
--- /dev/null
+++ b/gspell/gspell-icu.h
@@ -0,0 +1,58 @@
+/*
+ * This file is part of gspell, a spell-checking library.
+ *
+ * Copyright 2020 - Sébastien Wilmet <swilmet gnome org>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GSPELL_ICU_H
+#define GSPELL_ICU_H
+
+#include <glib.h>
+#include <unicode/ustring.h>
+
+G_BEGIN_DECLS
+
+G_GNUC_INTERNAL
+char *                 _gspell_icu_strToUTF8                   (int32_t     *pDestLength,
+                                                                const UChar *src,
+                                                                int32_t      srcLength,
+                                                                UErrorCode  *pErrorCode);
+
+G_GNUC_INTERNAL
+char *                 _gspell_icu_strToUTF8Simple             (const UChar *uchars);
+
+G_GNUC_INTERNAL
+UChar *                        _gspell_icu_loc_getDisplayName          (const char *localeID,
+                                                                const char *inLocaleID,
+                                                                UErrorCode *err);
+
+G_GNUC_INTERNAL
+char *                 _gspell_icu_loc_getDisplayNameSimple    (const char *localeID,
+                                                                const char *inLocaleID);
+
+G_GNUC_INTERNAL
+char *                 _gspell_icu_loc_canonicalize            (const char *localeID,
+                                                                UErrorCode *err);
+
+G_GNUC_INTERNAL
+char *                 _gspell_icu_loc_canonicalizeSimple      (const char *localeID);
+
+G_GNUC_INTERNAL
+char *                 _gspell_icu_get_language_name_from_code (const char *language_code);
+
+G_END_DECLS
+
+#endif /* GSPELL_ICU_H */
diff --git a/po/POTFILES.in b/po/POTFILES.in
index f10bd5a..8cc92b9 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -6,6 +6,7 @@ gspell/gspell-current-word-policy.c
 gspell/gspell-entry.c
 gspell/gspell-entry-buffer.c
 gspell/gspell-entry-utils.c
+gspell/gspell-icu.c
 gspell/gspell-inline-checker-text-buffer.c
 gspell/gspell-language.c
 gspell/gspell-language-chooser.c
diff --git a/testsuite/Makefile.am b/testsuite/Makefile.am
index c58a176..4bda3f6 100644
--- a/testsuite/Makefile.am
+++ b/testsuite/Makefile.am
@@ -31,6 +31,9 @@ test_checker_SOURCES = test-checker.c
 UNIT_TEST_PROGS += test-entry
 test_entry_SOURCES = test-entry.c
 
+UNIT_TEST_PROGS += test-icu
+test_icu_SOURCES = test-icu.c
+
 UNIT_TEST_PROGS += test-inline-checker-text-buffer
 test_inline_checker_text_buffer_SOURCES = test-inline-checker-text-buffer.c
 
diff --git a/testsuite/test-icu.c b/testsuite/test-icu.c
new file mode 100644
index 0000000..363575e
--- /dev/null
+++ b/testsuite/test-icu.c
@@ -0,0 +1,49 @@
+/*
+ * This file is part of gspell, a spell-checking library.
+ *
+ * Copyright 2020 - Sébastien Wilmet <swilmet gnome org>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gtk/gtk.h>
+#include "gspell/gspell-icu.h"
+
+static void
+check_loc_getDisplayNameSimple (const char *localeID,
+                               const char *expected_display_name)
+{
+       char *received_display_name;
+
+       received_display_name = _gspell_icu_loc_getDisplayNameSimple (localeID, "en_US");
+       g_assert_cmpstr (received_display_name, ==, expected_display_name);
+       g_free (received_display_name);
+}
+
+static void
+test_loc_getDisplayNameSimple (void)
+{
+       check_loc_getDisplayNameSimple ("en_US", "English (United States)");
+}
+
+int
+main (int    argc,
+      char **argv)
+{
+       gtk_test_init (&argc, &argv);
+
+       g_test_add_func ("/icu/loc_getDisplayNameSimple", test_loc_getDisplayNameSimple);
+
+       return g_test_run ();
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]