* i18n, gettext support
@ 2004-08-20 20:26 Bruno Haible
2004-08-23 0:58 ` Kevin Ryde
2004-09-01 16:25 ` Jan Nieuwenhuizen
0 siblings, 2 replies; 28+ messages in thread
From: Bruno Haible @ 2004-08-20 20:26 UTC (permalink / raw)
Cc: Jan Nieuwenhuizen
[-- Attachment #1: Type: text/plain, Size: 1983 bytes --]
Hello,
Jan Nieuwenhuizen asked me (the GNU gettext maintainer) for how to support
Guile programs in gettext.
The idea would be to make libintl bindings at the C level, and add support
for Scheme to xgettext and msgfmt. Common Lisp support has already been done
long ago; the guile support would therefore be a simple clone of it.
I plan to use this sample "hello world" program as an example. Is this OK
with you, the guile developers?
=============================== hello.scm ==================================
#!@GUILE@ -s
!#
;;; Example for use of GNU gettext.
;;; Copyright (C) 2004 Free Software Foundation, Inc.
;;; This file is in the public domain.
;;; Source code of the GNU guile program.
(use-modules (i18n))
(use-modules (ice-9 format))
(set! (i18n:textdomain) "hello-guile")
(set! (i18n:textdomaindir "hello-guile") "@localedir@/")
(define _ i18n:gettext)
(display (_ "Hello, world!"))
(newline)
(format #t (_ "This program is running as process number ~D.") (getpid))
(newline)
=============================================================================
Attached you find my proposal for the libintl binding module. It is based
on the existing interface in GNU clisp, and adapted for guile. Please
comment on it. You can use this proposal as a base for the documentation
of this interface.
Technically, this binding could be distributed with guile or with gettext.
I would much prefer if it were part of guile, because this frees the
guile user from checking whether the guile-libintl interface is installed
or not.
The ice-9 format string facility with its ~n@* facility is sufficient for
i18n. Is it true that most guile programs use format, not printf, for
formatted string output?
> without guile properly understanding multi-byte strings it's a bit limited
Without proper multibyte or Unicode string support, programs can not
do surgery (truncation, uppercase conversion etc.) on strings returned
from i18n:gettext, but it can output them.
Bruno
[-- Attachment #2: guile-gettext.html --]
[-- Type: text/html, Size: 17344 bytes --]
[-- Attachment #3: Type: text/plain, Size: 143 bytes --]
_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: i18n, gettext support 2004-08-20 20:26 i18n, gettext support Bruno Haible @ 2004-08-23 0:58 ` Kevin Ryde 2004-09-01 16:25 ` Jan Nieuwenhuizen 1 sibling, 0 replies; 28+ messages in thread From: Kevin Ryde @ 2004-08-23 0:58 UTC (permalink / raw) Cc: guile-devel, Jan Nieuwenhuizen Bruno Haible <bruno@clisp.org> writes: > > (use-modules (i18n)) It's probably important enough to have in the core. > (set! (i18n:textdomain) "hello-guile") I'd just call the functions plain "textdomain" etc. > (define _ i18n:gettext) Could provide that binding by default, to encourage its use. > The ice-9 format string facility with its ~n@* facility is sufficient for > i18n. Many programs probably use only the core `simple-format' version of format, which lacks ~*. Might be worth adding there. _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: i18n, gettext support 2004-08-20 20:26 i18n, gettext support Bruno Haible 2004-08-23 0:58 ` Kevin Ryde @ 2004-09-01 16:25 ` Jan Nieuwenhuizen 2004-09-01 20:57 ` Bruno Haible 2004-09-01 21:44 ` Kevin Ryde 1 sibling, 2 replies; 28+ messages in thread From: Jan Nieuwenhuizen @ 2004-09-01 16:25 UTC (permalink / raw) Cc: guile-devel [-- Attachment #1: Type: text/plain, Size: 323 bytes --] Bruno Haible writes: > I plan to use this sample "hello world" program as an example. Is this OK > with you, the guile developers? Attached is a patch with gettext C bindings for GUILE (which I tried to avoid before). When this gets included in GUILE, we can make the final changes to hello-guile.scm. Greetings, Jan. [-- Attachment #2: guile-1.7.1.jcn1.diff --] [-- Type: text/plain, Size: 9687 bytes --] ? debug ? doconf ? guile-config/libtool.m4 ? guile-config/ltdl.m4 ? guile-readline/ice-9 ? guile-readline/libtool.m4 ? libguile/i18n.c ? libguile/i18n.h ? libguile/init.loT Index: ChangeLog =================================================================== RCS file: /cvsroot/guile/guile/guile-core/ChangeLog,v retrieving revision 1.444 diff -p -u -r1.444 ChangeLog --- ChangeLog 27 Aug 2004 01:10:20 -0000 1.444 +++ ChangeLog 1 Sep 2004 16:17:14 -0000 @@ -1,3 +1,7 @@ +2004-09-01 Jan Nieuwenhuizen <janneke@gnu.org> + + * configure.in: Add i18n checks. + 2004-08-27 Kevin Ryde <user42@zip.com.au> * configure.in (AC_CHECK_MEMBERS): Add struct sockaddr.sin_len and Index: configure.in =================================================================== RCS file: /cvsroot/guile/guile/guile-core/configure.in,v retrieving revision 1.251 diff -p -u -r1.251 configure.in --- configure.in 27 Aug 2004 01:09:48 -0000 1.251 +++ configure.in 1 Sep 2004 16:17:14 -0000 @@ -637,6 +637,14 @@ AC_TRY_LINK([#include <gmp.h>], [mpz_import (0, 0, 0, 0, 0, 0, 0);] , , [AC_MSG_ERROR([At least GNU MP 4.1 is required, see http://swox.com/gmp])]) +dnl i18n tests +AC_CHECK_HEADERS([gettext.h libintl.h]) +AC_CHECK_FUNCS(gettext) +if test $ac_cv_func_gettext = no; then + AC_CHECK_LIB(intl, gettext) +fi +AC_CHECK_FUNCS([bindtextdomain textdomain]) + ### Some systems don't declare some functions. On such systems, we ### need to at least provide our own K&R-style declarations. Index: libguile/ChangeLog =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/ChangeLog,v retrieving revision 1.2137 diff -p -u -r1.2137 ChangeLog --- libguile/ChangeLog 27 Aug 2004 12:46:11 -0000 1.2137 +++ libguile/ChangeLog 1 Sep 2004 16:17:17 -0000 @@ -1,3 +1,8 @@ +2004-09-01 Jan Nieuwenhuizen <janneke@gnu.org> + + * i18n.h: + * i18n.c: New file. + 2004-08-27 Marius Vollmer <marius.vollmer@uni-dortmund.de> * strings.c (SCM_STRINGP): Accept all strings. Index: libguile/Makefile.am =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/Makefile.am,v retrieving revision 1.191 diff -p -u -r1.191 Makefile.am --- libguile/Makefile.am 24 Aug 2004 22:11:35 -0000 1.191 +++ libguile/Makefile.am 1 Sep 2004 16:17:17 -0000 @@ -97,7 +97,7 @@ libguile_la_SOURCES = alist.c arbiters.c gc.c gc-mark.c gc-segment.c gc-malloc.c gc-card.c gc-freelist.c \ gc_os_dep.c gdbint.c gh_data.c gh_eval.c gh_funcs.c gh_init.c \ gh_io.c gh_list.c gh_predicates.c goops.c gsubr.c guardians.c hash.c \ - hashtab.c hooks.c init.c inline.c ioext.c keywords.c \ + hashtab.c hooks.c i18n.c init.c inline.c ioext.c keywords.c \ lang.c list.c \ load.c macros.c mallocs.c modules.c numbers.c objects.c objprop.c \ options.c pairs.c ports.c print.c procprop.c procs.c properties.c \ @@ -113,7 +113,7 @@ DOT_X_FILES = alist.x arbiters.x async.x error.x eval.x evalext.x extensions.x feature.x fluids.x fports.x \ futures.x \ gc.x gc-mark.x gc-segment.x gc-malloc.x gc-card.x goops.x \ - gsubr.x guardians.x hash.x hashtab.x hooks.x init.x ioext.x \ + gsubr.x guardians.x hash.x hashtab.x hooks.x i18n.x init.x ioext.x \ keywords.x lang.x list.x load.x macros.x mallocs.x modules.x \ numbers.x objects.x objprop.x options.x pairs.x ports.x print.x \ procprop.x procs.x properties.x random.x rdelim.x read.x root.x rw.x \ @@ -187,7 +187,7 @@ modinclude_HEADERS = __scm.h alist.h arb error.h eval.h \ evalext.h extensions.h feature.h filesys.h fluids.h fports.h futures.h \ gc.h gdb_interface.h gdbint.h \ - goops.h gsubr.h guardians.h hash.h hashtab.h hooks.h init.h \ + goops.h gsubr.h guardians.h hash.h hashtab.h hooks.h i18n.h init.h \ inline.h ioext.h \ iselect.h keywords.h lang.h list.h load.h macros.h mallocs.h modules.h \ net_db.h numbers.h objects.h objprop.h options.h pairs.h ports.h posix.h \ Index: libguile/init.c =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/init.c,v retrieving revision 1.159 diff -p -u -r1.159 init.c --- libguile/init.c 24 Aug 2004 22:13:07 -0000 1.159 +++ libguile/init.c 1 Sep 2004 16:17:17 -0000 @@ -477,6 +477,7 @@ scm_init_guile_1 (SCM_STACKITEM *base) scm_init_properties (); scm_init_hooks (); /* Requires smob_prehistory */ scm_init_gc (); /* Requires hooks, async */ + scm_init_i18n (); scm_init_ioext (); scm_init_keywords (); scm_init_list (); Index: libguile/numbers.c =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/numbers.c,v retrieving revision 1.260 diff -p -u -r1.260 numbers.c --- libguile/numbers.c 24 Aug 2004 16:43:50 -0000 1.260 +++ libguile/numbers.c 1 Sep 2004 16:17:18 -0000 @@ -5848,8 +5848,8 @@ scm_init_numbers () scm_dblprec[10-2] = (DBL_DIG > 20) ? 20 : DBL_DIG; #endif -#ifdef GUILE_DEBUG - check_sanity (); +#ifdef FIXME__GUILE_DEBUG + check_sanity (); #endif exactly_one_half = scm_permanent_object (scm_divide (SCM_I_MAKINUM (1), --- ../ugh-cvs/libguile/libguile.h 1970-01-01 01:00:00 +0100 +++ libguile/i18n.h 2004-09-01 18:12:57 +0200 @@ -0,0 +1,43 @@ +/* classes: h_files */ + +#ifndef SCM_I18N_H +#define SCM_I18N_H + +/* Copyright (C) 2004 Free Software Foundation, Inc. + * + * 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 + */ + +\f + +#include "libguile/__scm.h" + +\f + + +\f + +SCM_API SCM scm_gettext (SCM string); +SCM_API SCM scm_textdomain (SCM domainname); +SCM_API SCM scm_bindtextdomain (SCM domainname, SCM directory); +SCM_API void scm_init_i18n (void); + +#endif /* SCM_I18N_H */ + +/* + Local Variables: + c-file-style: "gnu" + End: +*/ --- ../ugh-cvs/libguile/libguile.c 1970-01-01 01:00:00 +0100 +++ libguile/i18n.c 2004-09-01 17:38:29 +0200 @@ -0,0 +1,116 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + * + * 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 + */ + + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +#ifdef HAVE_GETEXT_H +# include <gettext.h> +#endif + +#ifdef HAVE_LIBINTL_H +# include <libintl.h> +#endif + +#include "libguile/_scm.h" +#include "libguile/discouraged.h" +#include "libguile/feature.h" +#include "libguile/i18n.h" +#include "libguile/strings.h" + +\f + +#ifdef HAVE_GETTEXT +SCM_DEFINE (scm_gettext, "gettext", 1, 0, 0, + (SCM string), + "Return gettext lookup of @var{string}.") +#define FUNC_NAME s_scm_gettext +{ + SCM_VALIDATE_STRING (1, string); + return scm_makfrom0str (gettext (SCM_STRING_CHARS (string))); +} +#undef FUNC_NAME +#endif /* HAVE_GETTEXT */ + +#ifdef HAVE_TEXTDOMAIN +SCM_DEFINE (scm_textdomain, "textdomain", 0, 1, 0, + (SCM domainname), + "If optional argument @var{domainname} is supplied, " + "set textdomain." + "Return the textdomain.") +#define FUNC_NAME s_scm_textdomain +{ + char *rv; + char *n; + + if (SCM_UNBNDP (domainname)) + n = NULL; + else + { + SCM_VALIDATE_STRING (1, domainname); + n = SCM_STRING_CHARS (domainname); + } + rv = textdomain (n); + if (rv == NULL) + SCM_SYSERROR; + return scm_makfrom0str (rv); +} +#undef FUNC_NAME +#endif /* HAVE_TEXTDOMAIN */ + +#ifdef HAVE_BINDTEXTDOMAIN +SCM_DEFINE (scm_bindtextdomain, "bindtextdomain", 1, 1, 0, + (SCM domainname, SCM directory), + "Set message catalogs for domain @var{domainname} " + "to directory @{directory}." + "Return the bound directory.") +#define FUNC_NAME s_scm_bindtextdomain +{ + char *rv; + char *d; + + SCM_VALIDATE_STRING (1, domainname); + if (SCM_UNBNDP (directory)) + d = NULL; + else + { + SCM_VALIDATE_STRING (2, directory); + d = SCM_STRING_CHARS (directory); + } + rv = bindtextdomain (SCM_STRING_CHARS (domainname), d); + if (rv == NULL) + SCM_SYSERROR; + return scm_makfrom0str (rv); +} +#undef FUNC_NAME +#endif /* HAVE_BINDTEXTDOMAIN */ + +void +scm_init_i18n () +{ + scm_add_feature ("i18n"); +#include "libguile/i18n.x" +} + + +/* + Local Variables: + c-file-style: "gnu" + End: +*/ [-- Attachment #3: Type: text/plain, Size: 141 bytes --] -- Jan Nieuwenhuizen <janneke@gnu.org> | GNU LilyPond - The music typesetter http://www.xs4all.nl/~jantien | http://www.lilypond.org [-- Attachment #4: Type: text/plain, Size: 143 bytes --] _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: i18n, gettext support 2004-09-01 16:25 ` Jan Nieuwenhuizen @ 2004-09-01 20:57 ` Bruno Haible 2004-09-02 9:38 ` Jan Nieuwenhuizen 2004-09-01 21:44 ` Kevin Ryde 1 sibling, 1 reply; 28+ messages in thread From: Bruno Haible @ 2004-09-01 20:57 UTC (permalink / raw) Cc: guile-devel Jan Nieuwenhuizen wrote: > Attached is a patch with gettext C bindings for GUILE (which I tried > to avoid before). Thanks; this is a good start. The patch is not complete however: it implements only half of the proposed API; the autoconf text for libintl is broken; and the use of gettext.h is useless since gettext.h should never be installed in public directories. I'll send an updated patch tomorrow. Bruno _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: i18n, gettext support 2004-09-01 20:57 ` Bruno Haible @ 2004-09-02 9:38 ` Jan Nieuwenhuizen 2004-09-02 16:06 ` Bruno Haible 0 siblings, 1 reply; 28+ messages in thread From: Jan Nieuwenhuizen @ 2004-09-02 9:38 UTC (permalink / raw) Cc: guile-devel [-- Attachment #1: Type: text/plain, Size: 580 bytes --] Bruno Haible writes: > Thanks; this is a good start. The patch is not complete however: it > implements only half of the proposed API; I have implemented the minimal functionality; the biggest hurdle is probably getting this included (I can hardly imagine how a software in 2004 could still lack gettext -- and be widely used). > the autoconf text for libintl is broken; and the use of gettext.h is > useless since gettext.h should never be installed in public > directories. Thanks, these should be fixed, see attached. > I'll send an updated patch tomorrow. Great. Jan. [-- Attachment #2: guile-1.7.1.jcn2.diff --] [-- Type: text/plain, Size: 9922 bytes --] ? debug ? do-diff ? doconf ? guile-1.7.1.jcn1.diff ? guile-1.7.1.jcn2.diff ? guile-config/libtool.m4 ? guile-config/ltdl.m4 ? guile-readline/ice-9 ? guile-readline/libtool.m4 ? libguile/' ? libguile/i18n.c ? libguile/i18n.h Index: ChangeLog =================================================================== RCS file: /cvsroot/guile/guile/guile-core/ChangeLog,v retrieving revision 1.444 diff -p -u -r1.444 ChangeLog --- ChangeLog 27 Aug 2004 01:10:20 -0000 1.444 +++ ChangeLog 2 Sep 2004 09:27:59 -0000 @@ -1,3 +1,7 @@ +2004-09-01 Jan Nieuwenhuizen <janneke@gnu.org> + + * configure.in: Add i18n tests. + 2004-08-27 Kevin Ryde <user42@zip.com.au> * configure.in (AC_CHECK_MEMBERS): Add struct sockaddr.sin_len and Index: configure.in =================================================================== RCS file: /cvsroot/guile/guile/guile-core/configure.in,v retrieving revision 1.251 diff -p -u -r1.251 configure.in --- configure.in 27 Aug 2004 01:09:48 -0000 1.251 +++ configure.in 2 Sep 2004 09:27:59 -0000 @@ -637,6 +637,14 @@ AC_TRY_LINK([#include <gmp.h>], [mpz_import (0, 0, 0, 0, 0, 0, 0);] , , [AC_MSG_ERROR([At least GNU MP 4.1 is required, see http://swox.com/gmp])]) +dnl i18n tests +AC_CHECK_HEADERS([libintl.h]) +AC_CHECK_FUNCS(gettext) +if test $ac_cv_func_gettext = no; then + AC_CHECK_LIB(intl, gettext) +fi +AC_CHECK_FUNCS([bindtextdomain textdomain]) + ### Some systems don't declare some functions. On such systems, we ### need to at least provide our own K&R-style declarations. Index: libguile/ChangeLog =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/ChangeLog,v retrieving revision 1.2137 diff -p -u -r1.2137 ChangeLog --- libguile/ChangeLog 27 Aug 2004 12:46:11 -0000 1.2137 +++ libguile/ChangeLog 2 Sep 2004 09:28:02 -0000 @@ -1,3 +1,11 @@ +2004-09-02 Jan Nieuwenhuizen <janneke@gnu.org> + + * i18n.h: + * i18n.c: New file. + + * init.c: + * Makefile.am: Add it. + 2004-08-27 Marius Vollmer <marius.vollmer@uni-dortmund.de> * strings.c (SCM_STRINGP): Accept all strings. Index: libguile/Makefile.am =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/Makefile.am,v retrieving revision 1.191 diff -p -u -r1.191 Makefile.am --- libguile/Makefile.am 24 Aug 2004 22:11:35 -0000 1.191 +++ libguile/Makefile.am 2 Sep 2004 09:28:02 -0000 @@ -97,7 +97,7 @@ libguile_la_SOURCES = alist.c arbiters.c gc.c gc-mark.c gc-segment.c gc-malloc.c gc-card.c gc-freelist.c \ gc_os_dep.c gdbint.c gh_data.c gh_eval.c gh_funcs.c gh_init.c \ gh_io.c gh_list.c gh_predicates.c goops.c gsubr.c guardians.c hash.c \ - hashtab.c hooks.c init.c inline.c ioext.c keywords.c \ + hashtab.c hooks.c i18n.c init.c inline.c ioext.c keywords.c \ lang.c list.c \ load.c macros.c mallocs.c modules.c numbers.c objects.c objprop.c \ options.c pairs.c ports.c print.c procprop.c procs.c properties.c \ @@ -113,7 +113,7 @@ DOT_X_FILES = alist.x arbiters.x async.x error.x eval.x evalext.x extensions.x feature.x fluids.x fports.x \ futures.x \ gc.x gc-mark.x gc-segment.x gc-malloc.x gc-card.x goops.x \ - gsubr.x guardians.x hash.x hashtab.x hooks.x init.x ioext.x \ + gsubr.x guardians.x hash.x hashtab.x hooks.x i18n.x init.x ioext.x \ keywords.x lang.x list.x load.x macros.x mallocs.x modules.x \ numbers.x objects.x objprop.x options.x pairs.x ports.x print.x \ procprop.x procs.x properties.x random.x rdelim.x read.x root.x rw.x \ @@ -187,7 +187,7 @@ modinclude_HEADERS = __scm.h alist.h arb error.h eval.h \ evalext.h extensions.h feature.h filesys.h fluids.h fports.h futures.h \ gc.h gdb_interface.h gdbint.h \ - goops.h gsubr.h guardians.h hash.h hashtab.h hooks.h init.h \ + goops.h gsubr.h guardians.h hash.h hashtab.h hooks.h i18n.h init.h \ inline.h ioext.h \ iselect.h keywords.h lang.h list.h load.h macros.h mallocs.h modules.h \ net_db.h numbers.h objects.h objprop.h options.h pairs.h ports.h posix.h \ Index: libguile/init.c =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/init.c,v retrieving revision 1.159 diff -p -u -r1.159 init.c --- libguile/init.c 24 Aug 2004 22:13:07 -0000 1.159 +++ libguile/init.c 2 Sep 2004 09:28:02 -0000 @@ -63,6 +63,7 @@ #include "libguile/hash.h" #include "libguile/hashtab.h" #include "libguile/hooks.h" +#include "libguile/i18n.h" #include "libguile/iselect.h" #include "libguile/ioext.h" #include "libguile/keywords.h" @@ -477,6 +478,7 @@ scm_init_guile_1 (SCM_STACKITEM *base) scm_init_properties (); scm_init_hooks (); /* Requires smob_prehistory */ scm_init_gc (); /* Requires hooks, async */ + scm_init_i18n (); scm_init_ioext (); scm_init_keywords (); scm_init_list (); Index: libguile/numbers.c =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/numbers.c,v retrieving revision 1.260 diff -p -u -r1.260 numbers.c --- libguile/numbers.c 24 Aug 2004 16:43:50 -0000 1.260 +++ libguile/numbers.c 2 Sep 2004 09:28:03 -0000 @@ -5848,8 +5848,8 @@ scm_init_numbers () scm_dblprec[10-2] = (DBL_DIG > 20) ? 20 : DBL_DIG; #endif -#ifdef GUILE_DEBUG - check_sanity (); +#ifdef FIXME__GUILE_DEBUG + check_sanity (); #endif exactly_one_half = scm_permanent_object (scm_divide (SCM_I_MAKINUM (1), --- ../ugh-cvs/libguile/libguile.h 1970-01-01 01:00:00 +0100 +++ libguile/i18n.h 2004-09-01 18:12:57 +0200 @@ -0,0 +1,43 @@ +/* classes: h_files */ + +#ifndef SCM_I18N_H +#define SCM_I18N_H + +/* Copyright (C) 2004 Free Software Foundation, Inc. + * + * 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 + */ + +\f + +#include "libguile/__scm.h" + +\f + + +\f + +SCM_API SCM scm_gettext (SCM string); +SCM_API SCM scm_textdomain (SCM domainname); +SCM_API SCM scm_bindtextdomain (SCM domainname, SCM directory); +SCM_API void scm_init_i18n (void); + +#endif /* SCM_I18N_H */ + +/* + Local Variables: + c-file-style: "gnu" + End: +*/ --- ../ugh-cvs/libguile/libguile.c 1970-01-01 01:00:00 +0100 +++ libguile/i18n.c 2004-09-02 11:24:39 +0200 @@ -0,0 +1,113 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + * + * 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 + */ + + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +#if HAVE_LIBINTL_H +# include <libintl.h> +#endif + +#include "libguile/_scm.h" +#include "libguile/feature.h" +#include "libguile/i18n.h" +#include "libguile/strings.h" + +\f + +#if ! HAVE_GETTEXT +# define gettext(x) (x) +#endif + +SCM_DEFINE (scm_gettext, "gettext", 1, 0, 0, + (SCM string), + "Return gettext lookup of @var{string}.") +#define FUNC_NAME s_scm_gettext +{ + SCM_VALIDATE_STRING (1, string); + return scm_from_locale_string (gettext (SCM_STRING_CHARS (string))); +} +#undef FUNC_NAME + +#if HAVE_TEXTDOMAIN +SCM_DEFINE (scm_textdomain, "textdomain", 0, 1, 0, + (SCM domainname), + "If optional argument @var{domainname} is supplied, " + "set textdomain." + "Return the textdomain.") +#define FUNC_NAME s_scm_textdomain +{ + char *rv; + char *n; + + if (SCM_UNBNDP (domainname)) + n = NULL; + else + { + SCM_VALIDATE_STRING (1, domainname); + n = SCM_STRING_CHARS (domainname); + } + rv = textdomain (n); + if (rv == NULL) + SCM_SYSERROR; + return scm_from_locale_string (rv); +} +#undef FUNC_NAME +#endif /* HAVE_TEXTDOMAIN */ + +#if HAVE_BINDTEXTDOMAIN +SCM_DEFINE (scm_bindtextdomain, "bindtextdomain", 1, 1, 0, + (SCM domainname, SCM directory), + "Set message catalogs for domain @var{domainname} " + "to directory @{directory}." + "Return the bound directory.") +#define FUNC_NAME s_scm_bindtextdomain +{ + char *rv; + char *d; + + SCM_VALIDATE_STRING (1, domainname); + if (SCM_UNBNDP (directory)) + d = NULL; + else + { + SCM_VALIDATE_STRING (2, directory); + d = SCM_STRING_CHARS (directory); + } + rv = bindtextdomain (SCM_STRING_CHARS (domainname), d); + if (rv == NULL) + SCM_SYSERROR; + return scm_from_locale_string (rv); +} +#undef FUNC_NAME +#endif /* HAVE_BINDTEXTDOMAIN */ + +void +scm_init_i18n () +{ + scm_add_feature ("i18n"); +#include "libguile/i18n.x" +} + + +/* + Local Variables: + c-file-style: "gnu" + End: +*/ [-- Attachment #3: Type: text/plain, Size: 142 bytes --] -- Jan Nieuwenhuizen <janneke@gnu.org> | GNU LilyPond - The music typesetter http://www.xs4all.nl/~jantien | http://www.lilypond.org [-- Attachment #4: Type: text/plain, Size: 143 bytes --] _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: i18n, gettext support 2004-09-02 9:38 ` Jan Nieuwenhuizen @ 2004-09-02 16:06 ` Bruno Haible 2004-09-02 16:21 ` Bruno Haible 2004-09-02 17:32 ` Jan Nieuwenhuizen 0 siblings, 2 replies; 28+ messages in thread From: Bruno Haible @ 2004-09-02 16:06 UTC (permalink / raw) Cc: guile-devel [-- Attachment #1: Type: text/plain, Size: 1072 bytes --] Jan Nieuwenhuizen wrote: > Thanks, these should be fixed, see attached. The autoconf test is still broken: AC_CHECK_LIB(intl, gettext) doesn't work. Also your patch uses SCM_STRING_CHARS, which is deprecated and (as far as I can test) doesn't work (probably because it returns a not NUL terminated string). Find here an extended patch. It implements the complete functionality, including plural handling, different locale categories and access to bind_textdomain_codeset (which will probably be important for Gtk/GNOME applications). ChangeLog: 2004-09-02 Bruno Haible <bruno@clisp.org> * configure.in: Add AM_GNU_GETTEXT invocation. libguile/ChangeLog: 2004-09-02 Jan Nieuwenhuizen <janneke@gnu.org> Bruno Haible <bruno@clisp.org> * i18n.h: New file. * i18n.c: New file. * init.c: Include libguile/i18n.h. (scm_init_guile_1): Add call to scm_init_i18n(). * Makefile.am (libguile_la_SOURCES): Add i18n.c. (DOT_X_FILES): Add i18n.x. (DOT_DOC_FILES): Add i18n.doc. (libguile_la_LDFLAGS): Add @LTLIBINTL@. (modinclude_HEADERS): Add i18n.h. [-- Attachment #2: guile-diffs --] [-- Type: text/x-diff, Size: 17890 bytes --] diff -r -c3 --exclude=Makefile --exclude='*.texi' --exclude='*.info*' --exclude=configure --exclude=Makefile.in guile-1.7.1.orig/configure.in guile-1.7.1/configure.in *** guile-1.7.1.orig/configure.in 2004-08-26 16:23:34.000000000 +0200 --- guile-1.7.1/configure.in 2004-09-01 22:05:51.000000000 +0200 *************** *** 637,642 **** --- 637,645 ---- [mpz_import (0, 0, 0, 0, 0, 0, 0);] , , [AC_MSG_ERROR([At least GNU MP 4.1 is required, see http://swox.com/gmp])]) + dnl i18n tests + AM_GNU_GETTEXT([external], [need-ngettext]) + ### Some systems don't declare some functions. On such systems, we ### need to at least provide our own K&R-style declarations. diff -r -c3 --exclude=Makefile --exclude='*.texi' --exclude='*.info*' --exclude=configure --exclude=Makefile.in guile-1.7.1.orig/libguile/init.c guile-1.7.1/libguile/init.c *** guile-1.7.1.orig/libguile/init.c 2004-08-25 11:45:13.000000000 +0200 --- guile-1.7.1/libguile/init.c 2004-09-02 13:43:11.000000000 +0200 *************** *** 63,68 **** --- 63,69 ---- #include "libguile/hash.h" #include "libguile/hashtab.h" #include "libguile/hooks.h" + #include "libguile/i18n.h" #include "libguile/iselect.h" #include "libguile/ioext.h" #include "libguile/keywords.h" *************** *** 477,482 **** --- 478,484 ---- scm_init_properties (); scm_init_hooks (); /* Requires smob_prehistory */ scm_init_gc (); /* Requires hooks, async */ + scm_init_i18n (); scm_init_ioext (); scm_init_keywords (); scm_init_list (); diff -r -c3 --exclude=Makefile --exclude='*.texi' --exclude='*.info*' --exclude=configure --exclude=Makefile.in guile-1.7.1.orig/libguile/Makefile.am guile-1.7.1/libguile/Makefile.am *** guile-1.7.1.orig/libguile/Makefile.am 2004-08-25 11:45:10.000000000 +0200 --- guile-1.7.1/libguile/Makefile.am 2004-09-02 17:47:55.000000000 +0200 *************** *** 97,103 **** gc.c gc-mark.c gc-segment.c gc-malloc.c gc-card.c gc-freelist.c \ gc_os_dep.c gdbint.c gh_data.c gh_eval.c gh_funcs.c gh_init.c \ gh_io.c gh_list.c gh_predicates.c goops.c gsubr.c guardians.c hash.c \ ! hashtab.c hooks.c init.c inline.c ioext.c keywords.c \ lang.c list.c \ load.c macros.c mallocs.c modules.c numbers.c objects.c objprop.c \ options.c pairs.c ports.c print.c procprop.c procs.c properties.c \ --- 97,103 ---- gc.c gc-mark.c gc-segment.c gc-malloc.c gc-card.c gc-freelist.c \ gc_os_dep.c gdbint.c gh_data.c gh_eval.c gh_funcs.c gh_init.c \ gh_io.c gh_list.c gh_predicates.c goops.c gsubr.c guardians.c hash.c \ ! hashtab.c hooks.c i18n.c init.c inline.c ioext.c keywords.c \ lang.c list.c \ load.c macros.c mallocs.c modules.c numbers.c objects.c objprop.c \ options.c pairs.c ports.c print.c procprop.c procs.c properties.c \ *************** *** 113,119 **** error.x eval.x evalext.x extensions.x feature.x fluids.x fports.x \ futures.x \ gc.x gc-mark.x gc-segment.x gc-malloc.x gc-card.x goops.x \ ! gsubr.x guardians.x hash.x hashtab.x hooks.x init.x ioext.x \ keywords.x lang.x list.x load.x macros.x mallocs.x modules.x \ numbers.x objects.x objprop.x options.x pairs.x ports.x print.x \ procprop.x procs.x properties.x random.x rdelim.x read.x root.x rw.x \ --- 113,119 ---- error.x eval.x evalext.x extensions.x feature.x fluids.x fports.x \ futures.x \ gc.x gc-mark.x gc-segment.x gc-malloc.x gc-card.x goops.x \ ! gsubr.x guardians.x hash.x hashtab.x hooks.x i18n.x init.x ioext.x \ keywords.x lang.x list.x load.x macros.x mallocs.x modules.x \ numbers.x objects.x objprop.x options.x pairs.x ports.x print.x \ procprop.x procs.x properties.x random.x rdelim.x read.x root.x rw.x \ *************** *** 132,139 **** extensions.doc feature.doc fluids.doc fports.doc futures.doc \ gc.doc goops.doc \ gsubr.doc gc-mark.doc gc-segment.doc gc-malloc.doc gc-card.doc \ ! guardians.doc hash.doc hashtab.doc hooks.doc init.doc ioext.doc \ ! keywords.doc lang.doc list.doc load.doc macros.doc \ mallocs.doc modules.doc numbers.doc objects.doc objprop.doc \ options.doc pairs.doc ports.doc print.doc procprop.doc \ procs.doc properties.doc random.doc rdelim.doc read.doc root.doc rw.doc \ --- 132,139 ---- extensions.doc feature.doc fluids.doc fports.doc futures.doc \ gc.doc goops.doc \ gsubr.doc gc-mark.doc gc-segment.doc gc-malloc.doc gc-card.doc \ ! guardians.doc hash.doc hashtab.doc hooks.doc i18n.doc init.doc \ ! ioext.doc keywords.doc lang.doc list.doc load.doc macros.doc \ mallocs.doc modules.doc numbers.doc objects.doc objprop.doc \ options.doc pairs.doc ports.doc print.doc procprop.doc \ procs.doc properties.doc random.doc rdelim.doc read.doc root.doc rw.doc \ *************** *** 172,178 **** libguile_la_DEPENDENCIES = @LIBLOBJS@ libguile_la_LIBADD = @LIBLOBJS@ ../libguile-ltdl/libguile-ltdl.la $(THREAD_LIBS_LOCAL) ! libguile_la_LDFLAGS = -version-info @LIBGUILE_INTERFACE_CURRENT@:@LIBGUILE_INTERFACE_REVISION@:@LIBGUILE_INTERFACE_AGE@ -export-dynamic -no-undefined # These are headers visible as <guile/mumble.h> pkginclude_HEADERS = gh.h --- 172,178 ---- libguile_la_DEPENDENCIES = @LIBLOBJS@ libguile_la_LIBADD = @LIBLOBJS@ ../libguile-ltdl/libguile-ltdl.la $(THREAD_LIBS_LOCAL) ! libguile_la_LDFLAGS = @LTLIBINTL@ -version-info @LIBGUILE_INTERFACE_CURRENT@:@LIBGUILE_INTERFACE_REVISION@:@LIBGUILE_INTERFACE_AGE@ -export-dynamic -no-undefined # These are headers visible as <guile/mumble.h> pkginclude_HEADERS = gh.h *************** *** 187,193 **** error.h eval.h \ evalext.h extensions.h feature.h filesys.h fluids.h fports.h futures.h \ gc.h gdb_interface.h gdbint.h \ ! goops.h gsubr.h guardians.h hash.h hashtab.h hooks.h init.h \ inline.h ioext.h \ iselect.h keywords.h lang.h list.h load.h macros.h mallocs.h modules.h \ net_db.h numbers.h objects.h objprop.h options.h pairs.h ports.h posix.h \ --- 187,193 ---- error.h eval.h \ evalext.h extensions.h feature.h filesys.h fluids.h fports.h futures.h \ gc.h gdb_interface.h gdbint.h \ ! goops.h gsubr.h guardians.h hash.h hashtab.h hooks.h i18n.h init.h \ inline.h ioext.h \ iselect.h keywords.h lang.h list.h load.h macros.h mallocs.h modules.h \ net_db.h numbers.h objects.h objprop.h options.h pairs.h ports.h posix.h \ *** /dev/null 1970-01-01 01:00:00.000000000 +0100 --- guile-1.7.1/libguile/i18n.h 2004-09-02 14:05:22.000000000 +0200 *************** *** 0 **** --- 1,41 ---- + /* classes: h_files */ + + #ifndef SCM_I18N_H + #define SCM_I18N_H + + /* Copyright (C) 2004 Free Software Foundation, Inc. + * + * 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 "libguile/__scm.h" + + SCM_API SCM scm_gettext (SCM msgid, SCM domainname, SCM category); + SCM_API SCM scm_ngettext (SCM msgid, SCM msgid_plural, SCM n, SCM domainname, SCM category); + SCM_API SCM scm_get_textdomain (void); + SCM_API SCM scm_set_textdomain (SCM domainname); + SCM_API SCM scm_get_textdomain_dir (SCM domainname); + SCM_API SCM scm_set_textdomain_dir (SCM domainname, SCM directory); + SCM_API SCM scm_get_textdomain_codeset (SCM domainname); + SCM_API SCM scm_set_textdomain_codeset (SCM domainname, SCM encoding); + SCM_API void scm_init_i18n (void); + + #endif /* SCM_I18N_H */ + + /* + Local Variables: + c-file-style: "gnu" + End: + */ *** /dev/null 1970-01-01 01:00:00.000000000 +0100 --- guile-1.7.1/libguile/i18n.c 2004-09-02 17:39:25.000000000 +0200 *************** *** 0 **** --- 1,334 ---- + /* Copyright (C) 2004 Free Software Foundation, Inc. + * + * 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 + */ + + + #if HAVE_CONFIG_H + # include <config.h> + #endif + + #include "libguile/_scm.h" + #include "libguile/discouraged.h" + #include "libguile/feature.h" + #include "libguile/i18n.h" + #include "libguile/strings.h" + #include "gettext.h" + #include <locale.h> + + + SCM_SYMBOL (scm_sym_LC_MESSAGES, "LC_MESSAGES"); + SCM_SYMBOL (scm_sym_LC_CTYPE, "LC_CTYPE"); + SCM_SYMBOL (scm_sym_LC_TIME, "LC_TIME"); + SCM_SYMBOL (scm_sym_LC_COLLATE, "LC_COLLATE"); + SCM_SYMBOL (scm_sym_LC_MONETARY, "LC_MONETARY"); + + + static int + scm_validate_category (SCM category, const char *subr, int pos) + { + if (scm_is_eq (category, scm_sym_LC_MESSAGES)) + return LC_MESSAGES; + else if (scm_is_eq (category, scm_sym_LC_CTYPE)) + return LC_CTYPE; + else if (scm_is_eq (category, scm_sym_LC_TIME)) + return LC_TIME; + else if (scm_is_eq (category, scm_sym_LC_COLLATE)) + return LC_COLLATE; + else if (scm_is_eq (category, scm_sym_LC_MONETARY)) + return LC_MONETARY; + else + scm_wrong_type_arg (subr, pos, category); + } + + + SCM_DEFINE (scm_gettext, "gettext", 1, 2, 0, + (SCM msgid, SCM domain, SCM category), + "Return the translation of @var{msgid} in the message domain " + "@var{domain}. @var{domain} is optional and defaults to the " + "domain set through (textdomain). @var{category} is optional " + "and defaults to LC_MESSAGES.") + #define FUNC_NAME s_scm_gettext + { + char *c_msgid; + const char *result; + + SCM_VALIDATE_STRING (1, msgid); + c_msgid = scm_to_locale_string (msgid); + if (SCM_UNBNDP (domain)) + { + /* 1 argument case. */ + result = gettext (c_msgid); + } + else + { + char *c_domain; + + SCM_VALIDATE_STRING (2, domain); + c_domain = scm_to_locale_string (domain); + if (SCM_UNBNDP (category)) + { + /* 2 argument case. */ + result = dgettext (c_domain, c_msgid); + } + else + { + /* 3 argument case. */ + int c_category; + + c_category = scm_validate_category (category, FUNC_NAME, 3); + result = dcgettext (c_domain, c_msgid, c_category); + } + free (c_domain); + } + + if (result == c_msgid) + { + free (c_msgid); + return msgid; + } + else + { + free (c_msgid); + return scm_makfrom0str (result); + } + } + #undef FUNC_NAME + + + SCM_DEFINE (scm_ngettext, "ngettext", 3, 2, 0, + (SCM msgid, SCM msgid_plural, SCM n, SCM domain, SCM category), + "Return the translation of @var{msgid}/@var{msgid_plural} in the " + "message domain @var{domain}, with the plural form being chosen " + "appropriately for the number @var{n}. @var{domain} is optional " + "and defaults to the domain set through (textdomain). " + "@var{category} is optional and defaults to LC_MESSAGES.") + #define FUNC_NAME s_scm_ngettext + { + char *c_msgid; + char *c_msgid_plural; + unsigned long c_n; + const char *result; + + SCM_VALIDATE_STRING (1, msgid); + c_msgid = scm_to_locale_string (msgid); + SCM_VALIDATE_STRING (2, msgid_plural); + c_msgid_plural = scm_to_locale_string (msgid_plural); + SCM_VALIDATE_ULONG_COPY (3, n, c_n); + if (SCM_UNBNDP (domain)) + { + /* 3 argument case. */ + result = ngettext (c_msgid, c_msgid_plural, c_n); + } + else + { + char *c_domain; + + SCM_VALIDATE_STRING (4, domain); + c_domain = scm_to_locale_string (domain); + if (SCM_UNBNDP (category)) + { + /* 4 argument case. */ + result = dngettext (c_domain, c_msgid, c_msgid_plural, c_n); + } + else + { + /* 5 argument case. */ + int c_category; + + c_category = scm_validate_category (category, FUNC_NAME, 5); + result = dcngettext (c_domain, c_msgid, c_msgid_plural, c_n, + c_category); + } + free (c_domain); + } + + if (result == c_msgid) + { + free (c_msgid_plural); + free (c_msgid); + return msgid; + } + else if (result == c_msgid_plural) + { + free (c_msgid_plural); + free (c_msgid); + return msgid_plural; + } + else + { + free (c_msgid_plural); + free (c_msgid); + return scm_makfrom0str (result); + } + } + #undef FUNC_NAME + + + SCM_DEFINE (scm_get_textdomain, "textdomain", 0, 0, 0, + (void), + "Return the current message domain.") + #define FUNC_NAME s_scm_get_textdomain + { + const char *result; + + result = textdomain (NULL); + if (result == NULL) + return SCM_BOOL_F; + else + return scm_makfrom0str (result); + } + #undef FUNC_NAME + + + SCM_DEFINE (scm_set_textdomain, "set!-textdomain", 1, 0, 0, + (SCM domain), + "Change the current message domain.") + #define FUNC_NAME s_scm_set_textdomain + { + char *c_domain; + + SCM_VALIDATE_STRING (1, domain); + c_domain = scm_to_locale_string (domain); + if (textdomain (c_domain) == NULL) + SCM_SYSERROR; + free (c_domain); + return domain; + } + #undef FUNC_NAME + + + SCM_DEFINE (scm_get_textdomain_dir, "textdomaindir", 1, 0, 0, + (SCM domain), + "Return the base directory for message catalogs for the given " + "message domain.") + #define FUNC_NAME s_scm_get_textdomain_dir + { + char *c_domain; + const char *result; + + SCM_VALIDATE_STRING (1, domain); + c_domain = scm_to_locale_string (domain); + result = bindtextdomain (c_domain, NULL); + free (c_domain); + if (result == NULL) + return SCM_BOOL_F; + else + return scm_makfrom0str (result); + } + #undef FUNC_NAME + + + SCM_DEFINE (scm_set_textdomain_dir, "set!-textdomaindir", 2, 0, 0, + (SCM domain, SCM directory), + "Change the base directory for message catalogs for the given " + "message domain.") + #define FUNC_NAME s_scm_set_textdomain_dir + { + char *c_domain; + char *c_directory; + + SCM_VALIDATE_STRING (1, domain); + SCM_VALIDATE_STRING (2, directory); + c_domain = scm_to_locale_string (domain); + c_directory = scm_to_locale_string (directory); + if (bindtextdomain (c_domain, c_directory) == NULL) + SCM_SYSERROR; + free (c_directory); + free (c_domain); + return directory; + } + #undef FUNC_NAME + + + SCM_DEFINE (scm_get_textdomain_codeset, "textdomain-codeset", 1, 0, 0, + (SCM domain), + "Return the encoding for message catalogs for the given message " + "domain.") + #define FUNC_NAME s_scm_get_textdomain_codeset + { + char *c_domain; + const char *result; + + SCM_VALIDATE_STRING (1, domain); + c_domain = scm_to_locale_string (domain); + result = bind_textdomain_codeset (c_domain, NULL); + free (c_domain); + if (result == NULL) + return SCM_BOOL_F; + else + return scm_makfrom0str (result); + } + #undef FUNC_NAME + + + SCM_DEFINE (scm_set_textdomain_codeset, "set!-textdomain-codeset", 2, 0, 0, + (SCM domain, SCM encoding), + "Change the encoding for message catalogs for the given message " + "domain.") + #define FUNC_NAME s_scm_set_textdomain_codeset + { + char *c_domain; + char *c_encoding; + + SCM_VALIDATE_STRING (1, domain); + SCM_VALIDATE_STRING (2, encoding); + c_domain = scm_to_locale_string (domain); + c_encoding = scm_to_locale_string (encoding); + if (bind_textdomain_codeset (c_domain, c_encoding) == NULL) + SCM_SYSERROR; + free (c_encoding); + free (c_domain); + return encoding; + } + #undef FUNC_NAME + + + void + scm_init_i18n () + { + SCM gettersym, settersym; + + scm_add_feature ("i18n"); + #include "libguile/i18n.x" + + gettersym = scm_c_lookup ("textdomain"); + settersym = scm_c_lookup ("set!-textdomain"); + SCM_VARIABLE_SET (gettersym, + scm_make_procedure_with_setter ( + SCM_VARIABLE_REF (gettersym), + SCM_VARIABLE_REF (settersym))); + + gettersym = scm_c_lookup ("textdomaindir"); + settersym = scm_c_lookup ("set!-textdomaindir"); + SCM_VARIABLE_SET (gettersym, + scm_make_procedure_with_setter ( + SCM_VARIABLE_REF (gettersym), + SCM_VARIABLE_REF (settersym))); + + gettersym = scm_c_lookup ("textdomain-codeset"); + settersym = scm_c_lookup ("set!-textdomain-codeset"); + SCM_VARIABLE_SET (gettersym, + scm_make_procedure_with_setter ( + SCM_VARIABLE_REF (gettersym), + SCM_VARIABLE_REF (settersym))); + } + + + /* + Local Variables: + c-file-style: "gnu" + End: + */ [-- Attachment #3: Type: text/plain, Size: 143 bytes --] _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: i18n, gettext support 2004-09-02 16:06 ` Bruno Haible @ 2004-09-02 16:21 ` Bruno Haible 2004-09-03 1:34 ` Kevin Ryde 2004-09-02 17:32 ` Jan Nieuwenhuizen 1 sibling, 1 reply; 28+ messages in thread From: Bruno Haible @ 2004-09-02 16:21 UTC (permalink / raw) Cc: guile-devel [-- Attachment #1: Type: text/plain, Size: 635 bytes --] Oops. Same thing once again, with gettext.h added. ChangeLog: 2004-09-02 Bruno Haible <bruno@clisp.org> * configure.in: Add AM_GNU_GETTEXT invocation. libguile/ChangeLog: 2004-09-02 Jan Nieuwenhuizen <janneke@gnu.org> Bruno Haible <bruno@clisp.org> * i18n.h: New file. * i18n.c: New file. * gettext.h: New file, taken from GNU gettext. * init.c: Include libguile/i18n.h. (scm_init_guile_1): Add call to scm_init_i18n(). * Makefile.am (libguile_la_SOURCES): Add i18n.c. (DOT_X_FILES): Add i18n.x. (DOT_DOC_FILES): Add i18n.doc. (libguile_la_LDFLAGS): Add @LTLIBINTL@. (modinclude_HEADERS): Add i18n.h. [-- Attachment #2: guile-diffs --] [-- Type: text/x-diff, Size: 21239 bytes --] diff -r -c3 --exclude=Makefile --exclude='*.texi' --exclude='*.info*' --exclude=configure --exclude=Makefile.in guile-1.7.1.orig/configure.in guile-1.7.1/configure.in *** guile-1.7.1.orig/configure.in 2004-08-26 16:23:34.000000000 +0200 --- guile-1.7.1/configure.in 2004-09-01 22:05:51.000000000 +0200 *************** *** 637,642 **** --- 637,645 ---- [mpz_import (0, 0, 0, 0, 0, 0, 0);] , , [AC_MSG_ERROR([At least GNU MP 4.1 is required, see http://swox.com/gmp])]) + dnl i18n tests + AM_GNU_GETTEXT([external], [need-ngettext]) + ### Some systems don't declare some functions. On such systems, we ### need to at least provide our own K&R-style declarations. diff -r -c3 --exclude=Makefile --exclude='*.texi' --exclude='*.info*' --exclude=configure --exclude=Makefile.in guile-1.7.1.orig/libguile/init.c guile-1.7.1/libguile/init.c *** guile-1.7.1.orig/libguile/init.c 2004-08-25 11:45:13.000000000 +0200 --- guile-1.7.1/libguile/init.c 2004-09-02 13:43:11.000000000 +0200 *************** *** 63,68 **** --- 63,69 ---- #include "libguile/hash.h" #include "libguile/hashtab.h" #include "libguile/hooks.h" + #include "libguile/i18n.h" #include "libguile/iselect.h" #include "libguile/ioext.h" #include "libguile/keywords.h" *************** *** 477,482 **** --- 478,484 ---- scm_init_properties (); scm_init_hooks (); /* Requires smob_prehistory */ scm_init_gc (); /* Requires hooks, async */ + scm_init_i18n (); scm_init_ioext (); scm_init_keywords (); scm_init_list (); diff -r -c3 --exclude=Makefile --exclude='*.texi' --exclude='*.info*' --exclude=configure --exclude=Makefile.in guile-1.7.1.orig/libguile/Makefile.am guile-1.7.1/libguile/Makefile.am *** guile-1.7.1.orig/libguile/Makefile.am 2004-08-25 11:45:10.000000000 +0200 --- guile-1.7.1/libguile/Makefile.am 2004-09-02 17:47:55.000000000 +0200 *************** *** 97,103 **** gc.c gc-mark.c gc-segment.c gc-malloc.c gc-card.c gc-freelist.c \ gc_os_dep.c gdbint.c gh_data.c gh_eval.c gh_funcs.c gh_init.c \ gh_io.c gh_list.c gh_predicates.c goops.c gsubr.c guardians.c hash.c \ ! hashtab.c hooks.c init.c inline.c ioext.c keywords.c \ lang.c list.c \ load.c macros.c mallocs.c modules.c numbers.c objects.c objprop.c \ options.c pairs.c ports.c print.c procprop.c procs.c properties.c \ --- 97,103 ---- gc.c gc-mark.c gc-segment.c gc-malloc.c gc-card.c gc-freelist.c \ gc_os_dep.c gdbint.c gh_data.c gh_eval.c gh_funcs.c gh_init.c \ gh_io.c gh_list.c gh_predicates.c goops.c gsubr.c guardians.c hash.c \ ! hashtab.c hooks.c i18n.c init.c inline.c ioext.c keywords.c \ lang.c list.c \ load.c macros.c mallocs.c modules.c numbers.c objects.c objprop.c \ options.c pairs.c ports.c print.c procprop.c procs.c properties.c \ *************** *** 113,119 **** error.x eval.x evalext.x extensions.x feature.x fluids.x fports.x \ futures.x \ gc.x gc-mark.x gc-segment.x gc-malloc.x gc-card.x goops.x \ ! gsubr.x guardians.x hash.x hashtab.x hooks.x init.x ioext.x \ keywords.x lang.x list.x load.x macros.x mallocs.x modules.x \ numbers.x objects.x objprop.x options.x pairs.x ports.x print.x \ procprop.x procs.x properties.x random.x rdelim.x read.x root.x rw.x \ --- 113,119 ---- error.x eval.x evalext.x extensions.x feature.x fluids.x fports.x \ futures.x \ gc.x gc-mark.x gc-segment.x gc-malloc.x gc-card.x goops.x \ ! gsubr.x guardians.x hash.x hashtab.x hooks.x i18n.x init.x ioext.x \ keywords.x lang.x list.x load.x macros.x mallocs.x modules.x \ numbers.x objects.x objprop.x options.x pairs.x ports.x print.x \ procprop.x procs.x properties.x random.x rdelim.x read.x root.x rw.x \ *************** *** 132,139 **** extensions.doc feature.doc fluids.doc fports.doc futures.doc \ gc.doc goops.doc \ gsubr.doc gc-mark.doc gc-segment.doc gc-malloc.doc gc-card.doc \ ! guardians.doc hash.doc hashtab.doc hooks.doc init.doc ioext.doc \ ! keywords.doc lang.doc list.doc load.doc macros.doc \ mallocs.doc modules.doc numbers.doc objects.doc objprop.doc \ options.doc pairs.doc ports.doc print.doc procprop.doc \ procs.doc properties.doc random.doc rdelim.doc read.doc root.doc rw.doc \ --- 132,139 ---- extensions.doc feature.doc fluids.doc fports.doc futures.doc \ gc.doc goops.doc \ gsubr.doc gc-mark.doc gc-segment.doc gc-malloc.doc gc-card.doc \ ! guardians.doc hash.doc hashtab.doc hooks.doc i18n.doc init.doc \ ! ioext.doc keywords.doc lang.doc list.doc load.doc macros.doc \ mallocs.doc modules.doc numbers.doc objects.doc objprop.doc \ options.doc pairs.doc ports.doc print.doc procprop.doc \ procs.doc properties.doc random.doc rdelim.doc read.doc root.doc rw.doc \ *************** *** 172,178 **** libguile_la_DEPENDENCIES = @LIBLOBJS@ libguile_la_LIBADD = @LIBLOBJS@ ../libguile-ltdl/libguile-ltdl.la $(THREAD_LIBS_LOCAL) ! libguile_la_LDFLAGS = -version-info @LIBGUILE_INTERFACE_CURRENT@:@LIBGUILE_INTERFACE_REVISION@:@LIBGUILE_INTERFACE_AGE@ -export-dynamic -no-undefined # These are headers visible as <guile/mumble.h> pkginclude_HEADERS = gh.h --- 172,178 ---- libguile_la_DEPENDENCIES = @LIBLOBJS@ libguile_la_LIBADD = @LIBLOBJS@ ../libguile-ltdl/libguile-ltdl.la $(THREAD_LIBS_LOCAL) ! libguile_la_LDFLAGS = @LTLIBINTL@ -version-info @LIBGUILE_INTERFACE_CURRENT@:@LIBGUILE_INTERFACE_REVISION@:@LIBGUILE_INTERFACE_AGE@ -export-dynamic -no-undefined # These are headers visible as <guile/mumble.h> pkginclude_HEADERS = gh.h *************** *** 187,193 **** error.h eval.h \ evalext.h extensions.h feature.h filesys.h fluids.h fports.h futures.h \ gc.h gdb_interface.h gdbint.h \ ! goops.h gsubr.h guardians.h hash.h hashtab.h hooks.h init.h \ inline.h ioext.h \ iselect.h keywords.h lang.h list.h load.h macros.h mallocs.h modules.h \ net_db.h numbers.h objects.h objprop.h options.h pairs.h ports.h posix.h \ --- 187,193 ---- error.h eval.h \ evalext.h extensions.h feature.h filesys.h fluids.h fports.h futures.h \ gc.h gdb_interface.h gdbint.h \ ! goops.h gsubr.h guardians.h hash.h hashtab.h hooks.h i18n.h init.h \ inline.h ioext.h \ iselect.h keywords.h lang.h list.h load.h macros.h mallocs.h modules.h \ net_db.h numbers.h objects.h objprop.h options.h pairs.h ports.h posix.h \ *** /dev/null 1970-01-01 01:00:00.000000000 +0100 --- guile-1.7.1/libguile/i18n.h 2004-09-02 14:05:22.000000000 +0200 *************** *** 0 **** --- 1,41 ---- + /* classes: h_files */ + + #ifndef SCM_I18N_H + #define SCM_I18N_H + + /* Copyright (C) 2004 Free Software Foundation, Inc. + * + * 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 "libguile/__scm.h" + + SCM_API SCM scm_gettext (SCM msgid, SCM domainname, SCM category); + SCM_API SCM scm_ngettext (SCM msgid, SCM msgid_plural, SCM n, SCM domainname, SCM category); + SCM_API SCM scm_get_textdomain (void); + SCM_API SCM scm_set_textdomain (SCM domainname); + SCM_API SCM scm_get_textdomain_dir (SCM domainname); + SCM_API SCM scm_set_textdomain_dir (SCM domainname, SCM directory); + SCM_API SCM scm_get_textdomain_codeset (SCM domainname); + SCM_API SCM scm_set_textdomain_codeset (SCM domainname, SCM encoding); + SCM_API void scm_init_i18n (void); + + #endif /* SCM_I18N_H */ + + /* + Local Variables: + c-file-style: "gnu" + End: + */ *** /dev/null 1970-01-01 01:00:00.000000000 +0100 --- guile-1.7.1/libguile/i18n.c 2004-09-02 17:39:25.000000000 +0200 *************** *** 0 **** --- 1,334 ---- + /* Copyright (C) 2004 Free Software Foundation, Inc. + * + * 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 + */ + + + #if HAVE_CONFIG_H + # include <config.h> + #endif + + #include "libguile/_scm.h" + #include "libguile/discouraged.h" + #include "libguile/feature.h" + #include "libguile/i18n.h" + #include "libguile/strings.h" + #include "gettext.h" + #include <locale.h> + + + SCM_SYMBOL (scm_sym_LC_MESSAGES, "LC_MESSAGES"); + SCM_SYMBOL (scm_sym_LC_CTYPE, "LC_CTYPE"); + SCM_SYMBOL (scm_sym_LC_TIME, "LC_TIME"); + SCM_SYMBOL (scm_sym_LC_COLLATE, "LC_COLLATE"); + SCM_SYMBOL (scm_sym_LC_MONETARY, "LC_MONETARY"); + + + static int + scm_validate_category (SCM category, const char *subr, int pos) + { + if (scm_is_eq (category, scm_sym_LC_MESSAGES)) + return LC_MESSAGES; + else if (scm_is_eq (category, scm_sym_LC_CTYPE)) + return LC_CTYPE; + else if (scm_is_eq (category, scm_sym_LC_TIME)) + return LC_TIME; + else if (scm_is_eq (category, scm_sym_LC_COLLATE)) + return LC_COLLATE; + else if (scm_is_eq (category, scm_sym_LC_MONETARY)) + return LC_MONETARY; + else + scm_wrong_type_arg (subr, pos, category); + } + + + SCM_DEFINE (scm_gettext, "gettext", 1, 2, 0, + (SCM msgid, SCM domain, SCM category), + "Return the translation of @var{msgid} in the message domain " + "@var{domain}. @var{domain} is optional and defaults to the " + "domain set through (textdomain). @var{category} is optional " + "and defaults to LC_MESSAGES.") + #define FUNC_NAME s_scm_gettext + { + char *c_msgid; + const char *result; + + SCM_VALIDATE_STRING (1, msgid); + c_msgid = scm_to_locale_string (msgid); + if (SCM_UNBNDP (domain)) + { + /* 1 argument case. */ + result = gettext (c_msgid); + } + else + { + char *c_domain; + + SCM_VALIDATE_STRING (2, domain); + c_domain = scm_to_locale_string (domain); + if (SCM_UNBNDP (category)) + { + /* 2 argument case. */ + result = dgettext (c_domain, c_msgid); + } + else + { + /* 3 argument case. */ + int c_category; + + c_category = scm_validate_category (category, FUNC_NAME, 3); + result = dcgettext (c_domain, c_msgid, c_category); + } + free (c_domain); + } + + if (result == c_msgid) + { + free (c_msgid); + return msgid; + } + else + { + free (c_msgid); + return scm_makfrom0str (result); + } + } + #undef FUNC_NAME + + + SCM_DEFINE (scm_ngettext, "ngettext", 3, 2, 0, + (SCM msgid, SCM msgid_plural, SCM n, SCM domain, SCM category), + "Return the translation of @var{msgid}/@var{msgid_plural} in the " + "message domain @var{domain}, with the plural form being chosen " + "appropriately for the number @var{n}. @var{domain} is optional " + "and defaults to the domain set through (textdomain). " + "@var{category} is optional and defaults to LC_MESSAGES.") + #define FUNC_NAME s_scm_ngettext + { + char *c_msgid; + char *c_msgid_plural; + unsigned long c_n; + const char *result; + + SCM_VALIDATE_STRING (1, msgid); + c_msgid = scm_to_locale_string (msgid); + SCM_VALIDATE_STRING (2, msgid_plural); + c_msgid_plural = scm_to_locale_string (msgid_plural); + SCM_VALIDATE_ULONG_COPY (3, n, c_n); + if (SCM_UNBNDP (domain)) + { + /* 3 argument case. */ + result = ngettext (c_msgid, c_msgid_plural, c_n); + } + else + { + char *c_domain; + + SCM_VALIDATE_STRING (4, domain); + c_domain = scm_to_locale_string (domain); + if (SCM_UNBNDP (category)) + { + /* 4 argument case. */ + result = dngettext (c_domain, c_msgid, c_msgid_plural, c_n); + } + else + { + /* 5 argument case. */ + int c_category; + + c_category = scm_validate_category (category, FUNC_NAME, 5); + result = dcngettext (c_domain, c_msgid, c_msgid_plural, c_n, + c_category); + } + free (c_domain); + } + + if (result == c_msgid) + { + free (c_msgid_plural); + free (c_msgid); + return msgid; + } + else if (result == c_msgid_plural) + { + free (c_msgid_plural); + free (c_msgid); + return msgid_plural; + } + else + { + free (c_msgid_plural); + free (c_msgid); + return scm_makfrom0str (result); + } + } + #undef FUNC_NAME + + + SCM_DEFINE (scm_get_textdomain, "textdomain", 0, 0, 0, + (void), + "Return the current message domain.") + #define FUNC_NAME s_scm_get_textdomain + { + const char *result; + + result = textdomain (NULL); + if (result == NULL) + return SCM_BOOL_F; + else + return scm_makfrom0str (result); + } + #undef FUNC_NAME + + + SCM_DEFINE (scm_set_textdomain, "set!-textdomain", 1, 0, 0, + (SCM domain), + "Change the current message domain.") + #define FUNC_NAME s_scm_set_textdomain + { + char *c_domain; + + SCM_VALIDATE_STRING (1, domain); + c_domain = scm_to_locale_string (domain); + if (textdomain (c_domain) == NULL) + SCM_SYSERROR; + free (c_domain); + return domain; + } + #undef FUNC_NAME + + + SCM_DEFINE (scm_get_textdomain_dir, "textdomaindir", 1, 0, 0, + (SCM domain), + "Return the base directory for message catalogs for the given " + "message domain.") + #define FUNC_NAME s_scm_get_textdomain_dir + { + char *c_domain; + const char *result; + + SCM_VALIDATE_STRING (1, domain); + c_domain = scm_to_locale_string (domain); + result = bindtextdomain (c_domain, NULL); + free (c_domain); + if (result == NULL) + return SCM_BOOL_F; + else + return scm_makfrom0str (result); + } + #undef FUNC_NAME + + + SCM_DEFINE (scm_set_textdomain_dir, "set!-textdomaindir", 2, 0, 0, + (SCM domain, SCM directory), + "Change the base directory for message catalogs for the given " + "message domain.") + #define FUNC_NAME s_scm_set_textdomain_dir + { + char *c_domain; + char *c_directory; + + SCM_VALIDATE_STRING (1, domain); + SCM_VALIDATE_STRING (2, directory); + c_domain = scm_to_locale_string (domain); + c_directory = scm_to_locale_string (directory); + if (bindtextdomain (c_domain, c_directory) == NULL) + SCM_SYSERROR; + free (c_directory); + free (c_domain); + return directory; + } + #undef FUNC_NAME + + + SCM_DEFINE (scm_get_textdomain_codeset, "textdomain-codeset", 1, 0, 0, + (SCM domain), + "Return the encoding for message catalogs for the given message " + "domain.") + #define FUNC_NAME s_scm_get_textdomain_codeset + { + char *c_domain; + const char *result; + + SCM_VALIDATE_STRING (1, domain); + c_domain = scm_to_locale_string (domain); + result = bind_textdomain_codeset (c_domain, NULL); + free (c_domain); + if (result == NULL) + return SCM_BOOL_F; + else + return scm_makfrom0str (result); + } + #undef FUNC_NAME + + + SCM_DEFINE (scm_set_textdomain_codeset, "set!-textdomain-codeset", 2, 0, 0, + (SCM domain, SCM encoding), + "Change the encoding for message catalogs for the given message " + "domain.") + #define FUNC_NAME s_scm_set_textdomain_codeset + { + char *c_domain; + char *c_encoding; + + SCM_VALIDATE_STRING (1, domain); + SCM_VALIDATE_STRING (2, encoding); + c_domain = scm_to_locale_string (domain); + c_encoding = scm_to_locale_string (encoding); + if (bind_textdomain_codeset (c_domain, c_encoding) == NULL) + SCM_SYSERROR; + free (c_encoding); + free (c_domain); + return encoding; + } + #undef FUNC_NAME + + + void + scm_init_i18n () + { + SCM gettersym, settersym; + + scm_add_feature ("i18n"); + #include "libguile/i18n.x" + + gettersym = scm_c_lookup ("textdomain"); + settersym = scm_c_lookup ("set!-textdomain"); + SCM_VARIABLE_SET (gettersym, + scm_make_procedure_with_setter ( + SCM_VARIABLE_REF (gettersym), + SCM_VARIABLE_REF (settersym))); + + gettersym = scm_c_lookup ("textdomaindir"); + settersym = scm_c_lookup ("set!-textdomaindir"); + SCM_VARIABLE_SET (gettersym, + scm_make_procedure_with_setter ( + SCM_VARIABLE_REF (gettersym), + SCM_VARIABLE_REF (settersym))); + + gettersym = scm_c_lookup ("textdomain-codeset"); + settersym = scm_c_lookup ("set!-textdomain-codeset"); + SCM_VARIABLE_SET (gettersym, + scm_make_procedure_with_setter ( + SCM_VARIABLE_REF (gettersym), + SCM_VARIABLE_REF (settersym))); + } + + + /* + Local Variables: + c-file-style: "gnu" + End: + */ *** /dev/null 1970-01-01 01:00:00.000000000 +0100 --- guile-1.7.1/libguile/gettext.h 2002-05-10 13:20:06.000000000 +0200 *************** *** 0 **** --- 1,69 ---- + /* Convenience header for conditional use of GNU <libintl.h>. + Copyright (C) 1995-1998, 2000-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + + #ifndef _LIBGETTEXT_H + #define _LIBGETTEXT_H 1 + + /* NLS can be disabled through the configure --disable-nls option. */ + #if ENABLE_NLS + + /* Get declarations of GNU message catalog functions. */ + # include <libintl.h> + + #else + + /* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which + chokes if dcgettext is defined as a macro. So include it now, to make + later inclusions of <locale.h> a NOP. We don't include <libintl.h> + as well because people using "gettext.h" will not include <libintl.h>, + and also including <libintl.h> would fail on SunOS 4, whereas <locale.h> + is OK. */ + #if defined(__sun) + # include <locale.h> + #endif + + /* Disabled NLS. + The casts to 'const char *' serve the purpose of producing warnings + for invalid uses of the value returned from these functions. + On pre-ANSI systems without 'const', the config.h file is supposed to + contain "#define const". */ + # define gettext(Msgid) ((const char *) (Msgid)) + # define dgettext(Domainname, Msgid) ((const char *) (Msgid)) + # define dcgettext(Domainname, Msgid, Category) ((const char *) (Msgid)) + # define ngettext(Msgid1, Msgid2, N) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) + # define dngettext(Domainname, Msgid1, Msgid2, N) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) + # define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) + # define textdomain(Domainname) ((const char *) (Domainname)) + # define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname)) + # define bind_textdomain_codeset(Domainname, Codeset) ((const char *) (Codeset)) + + #endif + + /* A pseudo function call that serves as a marker for the automated + extraction of messages, but does not call gettext(). The run-time + translation is done at a different place in the code. + The argument, String, should be a literal string. Concatenated strings + and other string expressions won't work. + The macro's expansion is not parenthesized, so that it is suitable as + initializer for static 'char[]' or 'const char[]' variables. */ + #define gettext_noop(String) String + + #endif /* _LIBGETTEXT_H */ [-- Attachment #3: Type: text/plain, Size: 143 bytes --] _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: i18n, gettext support 2004-09-02 16:21 ` Bruno Haible @ 2004-09-03 1:34 ` Kevin Ryde 2004-09-04 17:25 ` Bruno Haible 2004-09-07 8:20 ` Jan Nieuwenhuizen 0 siblings, 2 replies; 28+ messages in thread From: Kevin Ryde @ 2004-09-03 1:34 UTC (permalink / raw) Cc: guile-devel, Jan Nieuwenhuizen Bruno Haible <bruno@clisp.org> writes: > > + SCM_API SCM scm_get_textdomain (void); > + SCM_API SCM scm_set_textdomain (SCM domainname); I think these could be a single textdomain func taking an optional argument. That's what's done for setlocale for instance, and it matches the C routines. > + SCM_API SCM scm_get_textdomain_dir (SCM domainname); > + SCM_API SCM scm_set_textdomain_dir (SCM domainname, SCM directory); > + SCM_API SCM scm_get_textdomain_codeset (SCM domainname); > + SCM_API SCM scm_set_textdomain_codeset (SCM domainname, SCM encoding); And I'd call these bindtextdomain, again for similarity to the C routines they wrap. > + static int > + scm_validate_category (SCM category, const char *subr, int pos) > + { > + if (scm_is_eq (category, scm_sym_LC_MESSAGES)) > + return LC_MESSAGES; LC_MESSAGES and friends already exist as variables. > + SCM_VARIABLE_SET (gettersym, > + scm_make_procedure_with_setter ( > + SCM_VARIABLE_REF (gettersym), > + SCM_VARIABLE_REF (settersym))); Procedures with setters are not much used in the core. _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: i18n, gettext support 2004-09-03 1:34 ` Kevin Ryde @ 2004-09-04 17:25 ` Bruno Haible 2004-09-07 0:13 ` Kevin Ryde 2004-09-07 8:20 ` Jan Nieuwenhuizen 1 sibling, 1 reply; 28+ messages in thread From: Bruno Haible @ 2004-09-04 17:25 UTC (permalink / raw) Cc: guile-devel, Jan Nieuwenhuizen [-- Attachment #1: Type: text/plain, Size: 1369 bytes --] Kevin Ryde wrote: > LC_MESSAGES and friends already exist as variables. OK. Find attached a revised patch which takes this into account. > > + SCM_API SCM scm_get_textdomain (void); > > + SCM_API SCM scm_set_textdomain (SCM domainname); > > I think these could be a single textdomain func taking an optional > argument. That's what's done for setlocale for instance, and it > matches the C routines. > > > + SCM_API SCM scm_get_textdomain_dir (SCM domainname); > > + SCM_API SCM scm_set_textdomain_dir (SCM domainname, SCM directory); > > + SCM_API SCM scm_get_textdomain_codeset (SCM domainname); > > + SCM_API SCM scm_set_textdomain_codeset (SCM domainname, SCM encoding); > > And I'd call these bindtextdomain, again for similarity to the C > routines they wrap. > > > + SCM_VARIABLE_SET (gettersym, > > + scm_make_procedure_with_setter ( > > + SCM_VARIABLE_REF (gettersym), > > + SCM_VARIABLE_REF (settersym))); > > Procedures with setters are not much used in the core. That's your point of view, not mine. I would find it irresponsible if I were to submit a patch which includes destructive functions that don't bear a '!' in their name. You and/or Jan can of course spend 15 minutes to modify my patch to fit your point of view. In the GNU 'xgettext' extractor and associated example I will support whatever API you provide in guile. Bruno [-- Attachment #2: guile-diffs --] [-- Type: text/x-diff, Size: 21513 bytes --] ChangeLog: 2004-09-02 Bruno Haible <bruno@clisp.org> * configure.in: Add AM_GNU_GETTEXT invocation. libguile/ChangeLog: 2004-09-04 Jan Nieuwenhuizen <janneke@gnu.org> Bruno Haible <bruno@clisp.org> * i18n.h: New file. * i18n.c: New file. * gettext.h: New file, taken from GNU gettext. * init.c: Include libguile/i18n.h. (scm_init_guile_1): Add call to scm_init_i18n(). * Makefile.am (libguile_la_SOURCES): Add i18n.c. (DOT_X_FILES): Add i18n.x. (DOT_DOC_FILES): Add i18n.doc. (libguile_la_LDFLAGS): Add @LTLIBINTL@. (modinclude_HEADERS): Add i18n.h. diff -r -c3 --exclude=Makefile --exclude='*.texi' --exclude='*.info*' --exclude=configure --exclude=Makefile.in guile-1.7.1.orig/configure.in guile-1.7.1/configure.in *** guile-1.7.1.orig/configure.in 2004-08-26 16:23:34.000000000 +0200 --- guile-1.7.1/configure.in 2004-09-01 22:05:51.000000000 +0200 *************** *** 637,642 **** --- 637,645 ---- [mpz_import (0, 0, 0, 0, 0, 0, 0);] , , [AC_MSG_ERROR([At least GNU MP 4.1 is required, see http://swox.com/gmp])]) + dnl i18n tests + AM_GNU_GETTEXT([external], [need-ngettext]) + ### Some systems don't declare some functions. On such systems, we ### need to at least provide our own K&R-style declarations. diff -r -c3 --exclude=Makefile --exclude='*.texi' --exclude='*.info*' --exclude=configure --exclude=Makefile.in guile-1.7.1.orig/libguile/init.c guile-1.7.1/libguile/init.c *** guile-1.7.1.orig/libguile/init.c 2004-08-25 11:45:13.000000000 +0200 --- guile-1.7.1/libguile/init.c 2004-09-02 13:43:11.000000000 +0200 *************** *** 63,68 **** --- 63,69 ---- #include "libguile/hash.h" #include "libguile/hashtab.h" #include "libguile/hooks.h" + #include "libguile/i18n.h" #include "libguile/iselect.h" #include "libguile/ioext.h" #include "libguile/keywords.h" *************** *** 477,482 **** --- 478,484 ---- scm_init_properties (); scm_init_hooks (); /* Requires smob_prehistory */ scm_init_gc (); /* Requires hooks, async */ + scm_init_i18n (); scm_init_ioext (); scm_init_keywords (); scm_init_list (); diff -r -c3 --exclude=Makefile --exclude='*.texi' --exclude='*.info*' --exclude=configure --exclude=Makefile.in guile-1.7.1.orig/libguile/Makefile.am guile-1.7.1/libguile/Makefile.am *** guile-1.7.1.orig/libguile/Makefile.am 2004-08-25 11:45:10.000000000 +0200 --- guile-1.7.1/libguile/Makefile.am 2004-09-02 17:47:55.000000000 +0200 *************** *** 97,103 **** gc.c gc-mark.c gc-segment.c gc-malloc.c gc-card.c gc-freelist.c \ gc_os_dep.c gdbint.c gh_data.c gh_eval.c gh_funcs.c gh_init.c \ gh_io.c gh_list.c gh_predicates.c goops.c gsubr.c guardians.c hash.c \ ! hashtab.c hooks.c init.c inline.c ioext.c keywords.c \ lang.c list.c \ load.c macros.c mallocs.c modules.c numbers.c objects.c objprop.c \ options.c pairs.c ports.c print.c procprop.c procs.c properties.c \ --- 97,103 ---- gc.c gc-mark.c gc-segment.c gc-malloc.c gc-card.c gc-freelist.c \ gc_os_dep.c gdbint.c gh_data.c gh_eval.c gh_funcs.c gh_init.c \ gh_io.c gh_list.c gh_predicates.c goops.c gsubr.c guardians.c hash.c \ ! hashtab.c hooks.c i18n.c init.c inline.c ioext.c keywords.c \ lang.c list.c \ load.c macros.c mallocs.c modules.c numbers.c objects.c objprop.c \ options.c pairs.c ports.c print.c procprop.c procs.c properties.c \ *************** *** 113,119 **** error.x eval.x evalext.x extensions.x feature.x fluids.x fports.x \ futures.x \ gc.x gc-mark.x gc-segment.x gc-malloc.x gc-card.x goops.x \ ! gsubr.x guardians.x hash.x hashtab.x hooks.x init.x ioext.x \ keywords.x lang.x list.x load.x macros.x mallocs.x modules.x \ numbers.x objects.x objprop.x options.x pairs.x ports.x print.x \ procprop.x procs.x properties.x random.x rdelim.x read.x root.x rw.x \ --- 113,119 ---- error.x eval.x evalext.x extensions.x feature.x fluids.x fports.x \ futures.x \ gc.x gc-mark.x gc-segment.x gc-malloc.x gc-card.x goops.x \ ! gsubr.x guardians.x hash.x hashtab.x hooks.x i18n.x init.x ioext.x \ keywords.x lang.x list.x load.x macros.x mallocs.x modules.x \ numbers.x objects.x objprop.x options.x pairs.x ports.x print.x \ procprop.x procs.x properties.x random.x rdelim.x read.x root.x rw.x \ *************** *** 132,139 **** extensions.doc feature.doc fluids.doc fports.doc futures.doc \ gc.doc goops.doc \ gsubr.doc gc-mark.doc gc-segment.doc gc-malloc.doc gc-card.doc \ ! guardians.doc hash.doc hashtab.doc hooks.doc init.doc ioext.doc \ ! keywords.doc lang.doc list.doc load.doc macros.doc \ mallocs.doc modules.doc numbers.doc objects.doc objprop.doc \ options.doc pairs.doc ports.doc print.doc procprop.doc \ procs.doc properties.doc random.doc rdelim.doc read.doc root.doc rw.doc \ --- 132,139 ---- extensions.doc feature.doc fluids.doc fports.doc futures.doc \ gc.doc goops.doc \ gsubr.doc gc-mark.doc gc-segment.doc gc-malloc.doc gc-card.doc \ ! guardians.doc hash.doc hashtab.doc hooks.doc i18n.doc init.doc \ ! ioext.doc keywords.doc lang.doc list.doc load.doc macros.doc \ mallocs.doc modules.doc numbers.doc objects.doc objprop.doc \ options.doc pairs.doc ports.doc print.doc procprop.doc \ procs.doc properties.doc random.doc rdelim.doc read.doc root.doc rw.doc \ *************** *** 172,178 **** libguile_la_DEPENDENCIES = @LIBLOBJS@ libguile_la_LIBADD = @LIBLOBJS@ ../libguile-ltdl/libguile-ltdl.la $(THREAD_LIBS_LOCAL) ! libguile_la_LDFLAGS = -version-info @LIBGUILE_INTERFACE_CURRENT@:@LIBGUILE_INTERFACE_REVISION@:@LIBGUILE_INTERFACE_AGE@ -export-dynamic -no-undefined # These are headers visible as <guile/mumble.h> pkginclude_HEADERS = gh.h --- 172,178 ---- libguile_la_DEPENDENCIES = @LIBLOBJS@ libguile_la_LIBADD = @LIBLOBJS@ ../libguile-ltdl/libguile-ltdl.la $(THREAD_LIBS_LOCAL) ! libguile_la_LDFLAGS = @LTLIBINTL@ -version-info @LIBGUILE_INTERFACE_CURRENT@:@LIBGUILE_INTERFACE_REVISION@:@LIBGUILE_INTERFACE_AGE@ -export-dynamic -no-undefined # These are headers visible as <guile/mumble.h> pkginclude_HEADERS = gh.h *************** *** 187,193 **** error.h eval.h \ evalext.h extensions.h feature.h filesys.h fluids.h fports.h futures.h \ gc.h gdb_interface.h gdbint.h \ ! goops.h gsubr.h guardians.h hash.h hashtab.h hooks.h init.h \ inline.h ioext.h \ iselect.h keywords.h lang.h list.h load.h macros.h mallocs.h modules.h \ net_db.h numbers.h objects.h objprop.h options.h pairs.h ports.h posix.h \ --- 187,193 ---- error.h eval.h \ evalext.h extensions.h feature.h filesys.h fluids.h fports.h futures.h \ gc.h gdb_interface.h gdbint.h \ ! goops.h gsubr.h guardians.h hash.h hashtab.h hooks.h i18n.h init.h \ inline.h ioext.h \ iselect.h keywords.h lang.h list.h load.h macros.h mallocs.h modules.h \ net_db.h numbers.h objects.h objprop.h options.h pairs.h ports.h posix.h \ *** /dev/null 1970-01-01 01:00:00.000000000 +0100 --- guile-1.7.1/libguile/i18n.h 2004-09-02 14:05:22.000000000 +0200 *************** *** 0 **** --- 1,41 ---- + /* classes: h_files */ + + #ifndef SCM_I18N_H + #define SCM_I18N_H + + /* Copyright (C) 2004 Free Software Foundation, Inc. + * + * 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 "libguile/__scm.h" + + SCM_API SCM scm_gettext (SCM msgid, SCM domainname, SCM category); + SCM_API SCM scm_ngettext (SCM msgid, SCM msgid_plural, SCM n, SCM domainname, SCM category); + SCM_API SCM scm_get_textdomain (void); + SCM_API SCM scm_set_textdomain (SCM domainname); + SCM_API SCM scm_get_textdomain_dir (SCM domainname); + SCM_API SCM scm_set_textdomain_dir (SCM domainname, SCM directory); + SCM_API SCM scm_get_textdomain_codeset (SCM domainname); + SCM_API SCM scm_set_textdomain_codeset (SCM domainname, SCM encoding); + SCM_API void scm_init_i18n (void); + + #endif /* SCM_I18N_H */ + + /* + Local Variables: + c-file-style: "gnu" + End: + */ *** /dev/null 1970-01-01 01:00:00.000000000 +0100 --- guile-1.7.1/libguile/i18n.c 2004-09-04 19:10:24.000000000 +0200 *************** *** 0 **** --- 1,323 ---- + /* Copyright (C) 2004 Free Software Foundation, Inc. + * + * 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 + */ + + + #if HAVE_CONFIG_H + # include <config.h> + #endif + + #include "libguile/_scm.h" + #include "libguile/discouraged.h" + #include "libguile/feature.h" + #include "libguile/i18n.h" + #include "libguile/strings.h" + #include "gettext.h" + #include <locale.h> + + + static int + scm_validate_category (SCM category, const char *subr, int pos) + { + if (scm_is_eq (category, scm_from_int (LC_MESSAGES)) + || scm_is_eq (category, scm_from_int (LC_CTYPE)) + || scm_is_eq (category, scm_from_int (LC_TIME)) + || scm_is_eq (category, scm_from_int (LC_COLLATE)) + || scm_is_eq (category, scm_from_int (LC_MONETARY))) + return scm_to_int (category); + else + scm_wrong_type_arg (subr, pos, category); + } + + + SCM_DEFINE (scm_gettext, "gettext", 1, 2, 0, + (SCM msgid, SCM domain, SCM category), + "Return the translation of @var{msgid} in the message domain " + "@var{domain}. @var{domain} is optional and defaults to the " + "domain set through (textdomain). @var{category} is optional " + "and defaults to LC_MESSAGES.") + #define FUNC_NAME s_scm_gettext + { + char *c_msgid; + const char *result; + + SCM_VALIDATE_STRING (1, msgid); + c_msgid = scm_to_locale_string (msgid); + if (SCM_UNBNDP (domain)) + { + /* 1 argument case. */ + result = gettext (c_msgid); + } + else + { + char *c_domain; + + SCM_VALIDATE_STRING (2, domain); + c_domain = scm_to_locale_string (domain); + if (SCM_UNBNDP (category)) + { + /* 2 argument case. */ + result = dgettext (c_domain, c_msgid); + } + else + { + /* 3 argument case. */ + int c_category; + + c_category = scm_validate_category (category, FUNC_NAME, 3); + result = dcgettext (c_domain, c_msgid, c_category); + } + free (c_domain); + } + + if (result == c_msgid) + { + free (c_msgid); + return msgid; + } + else + { + free (c_msgid); + return scm_makfrom0str (result); + } + } + #undef FUNC_NAME + + + SCM_DEFINE (scm_ngettext, "ngettext", 3, 2, 0, + (SCM msgid, SCM msgid_plural, SCM n, SCM domain, SCM category), + "Return the translation of @var{msgid}/@var{msgid_plural} in the " + "message domain @var{domain}, with the plural form being chosen " + "appropriately for the number @var{n}. @var{domain} is optional " + "and defaults to the domain set through (textdomain). " + "@var{category} is optional and defaults to LC_MESSAGES.") + #define FUNC_NAME s_scm_ngettext + { + char *c_msgid; + char *c_msgid_plural; + unsigned long c_n; + const char *result; + + SCM_VALIDATE_STRING (1, msgid); + c_msgid = scm_to_locale_string (msgid); + SCM_VALIDATE_STRING (2, msgid_plural); + c_msgid_plural = scm_to_locale_string (msgid_plural); + SCM_VALIDATE_ULONG_COPY (3, n, c_n); + if (SCM_UNBNDP (domain)) + { + /* 3 argument case. */ + result = ngettext (c_msgid, c_msgid_plural, c_n); + } + else + { + char *c_domain; + + SCM_VALIDATE_STRING (4, domain); + c_domain = scm_to_locale_string (domain); + if (SCM_UNBNDP (category)) + { + /* 4 argument case. */ + result = dngettext (c_domain, c_msgid, c_msgid_plural, c_n); + } + else + { + /* 5 argument case. */ + int c_category; + + c_category = scm_validate_category (category, FUNC_NAME, 5); + result = dcngettext (c_domain, c_msgid, c_msgid_plural, c_n, + c_category); + } + free (c_domain); + } + + if (result == c_msgid) + { + free (c_msgid_plural); + free (c_msgid); + return msgid; + } + else if (result == c_msgid_plural) + { + free (c_msgid_plural); + free (c_msgid); + return msgid_plural; + } + else + { + free (c_msgid_plural); + free (c_msgid); + return scm_makfrom0str (result); + } + } + #undef FUNC_NAME + + + SCM_DEFINE (scm_get_textdomain, "textdomain", 0, 0, 0, + (void), + "Return the current message domain.") + #define FUNC_NAME s_scm_get_textdomain + { + const char *result; + + result = textdomain (NULL); + if (result == NULL) + return SCM_BOOL_F; + else + return scm_makfrom0str (result); + } + #undef FUNC_NAME + + + SCM_DEFINE (scm_set_textdomain, "set!-textdomain", 1, 0, 0, + (SCM domain), + "Change the current message domain.") + #define FUNC_NAME s_scm_set_textdomain + { + char *c_domain; + + SCM_VALIDATE_STRING (1, domain); + c_domain = scm_to_locale_string (domain); + if (textdomain (c_domain) == NULL) + SCM_SYSERROR; + free (c_domain); + return domain; + } + #undef FUNC_NAME + + + SCM_DEFINE (scm_get_textdomain_dir, "textdomaindir", 1, 0, 0, + (SCM domain), + "Return the base directory for message catalogs for the given " + "message domain.") + #define FUNC_NAME s_scm_get_textdomain_dir + { + char *c_domain; + const char *result; + + SCM_VALIDATE_STRING (1, domain); + c_domain = scm_to_locale_string (domain); + result = bindtextdomain (c_domain, NULL); + free (c_domain); + if (result == NULL) + return SCM_BOOL_F; + else + return scm_makfrom0str (result); + } + #undef FUNC_NAME + + + SCM_DEFINE (scm_set_textdomain_dir, "set!-textdomaindir", 2, 0, 0, + (SCM domain, SCM directory), + "Change the base directory for message catalogs for the given " + "message domain.") + #define FUNC_NAME s_scm_set_textdomain_dir + { + char *c_domain; + char *c_directory; + + SCM_VALIDATE_STRING (1, domain); + SCM_VALIDATE_STRING (2, directory); + c_domain = scm_to_locale_string (domain); + c_directory = scm_to_locale_string (directory); + if (bindtextdomain (c_domain, c_directory) == NULL) + SCM_SYSERROR; + free (c_directory); + free (c_domain); + return directory; + } + #undef FUNC_NAME + + + SCM_DEFINE (scm_get_textdomain_codeset, "textdomain-codeset", 1, 0, 0, + (SCM domain), + "Return the encoding for message catalogs for the given message " + "domain.") + #define FUNC_NAME s_scm_get_textdomain_codeset + { + char *c_domain; + const char *result; + + SCM_VALIDATE_STRING (1, domain); + c_domain = scm_to_locale_string (domain); + result = bind_textdomain_codeset (c_domain, NULL); + free (c_domain); + if (result == NULL) + return SCM_BOOL_F; + else + return scm_makfrom0str (result); + } + #undef FUNC_NAME + + + SCM_DEFINE (scm_set_textdomain_codeset, "set!-textdomain-codeset", 2, 0, 0, + (SCM domain, SCM encoding), + "Change the encoding for message catalogs for the given message " + "domain.") + #define FUNC_NAME s_scm_set_textdomain_codeset + { + char *c_domain; + char *c_encoding; + + SCM_VALIDATE_STRING (1, domain); + SCM_VALIDATE_STRING (2, encoding); + c_domain = scm_to_locale_string (domain); + c_encoding = scm_to_locale_string (encoding); + if (bind_textdomain_codeset (c_domain, c_encoding) == NULL) + SCM_SYSERROR; + free (c_encoding); + free (c_domain); + return encoding; + } + #undef FUNC_NAME + + + void + scm_init_i18n () + { + SCM gettersym, settersym; + + scm_add_feature ("i18n"); + #include "libguile/i18n.x" + + gettersym = scm_c_lookup ("textdomain"); + settersym = scm_c_lookup ("set!-textdomain"); + SCM_VARIABLE_SET (gettersym, + scm_make_procedure_with_setter ( + SCM_VARIABLE_REF (gettersym), + SCM_VARIABLE_REF (settersym))); + + gettersym = scm_c_lookup ("textdomaindir"); + settersym = scm_c_lookup ("set!-textdomaindir"); + SCM_VARIABLE_SET (gettersym, + scm_make_procedure_with_setter ( + SCM_VARIABLE_REF (gettersym), + SCM_VARIABLE_REF (settersym))); + + gettersym = scm_c_lookup ("textdomain-codeset"); + settersym = scm_c_lookup ("set!-textdomain-codeset"); + SCM_VARIABLE_SET (gettersym, + scm_make_procedure_with_setter ( + SCM_VARIABLE_REF (gettersym), + SCM_VARIABLE_REF (settersym))); + } + + + /* + Local Variables: + c-file-style: "gnu" + End: + */ *** /dev/null 1970-01-01 01:00:00.000000000 +0100 --- guile-1.7.1/libguile/gettext.h 2002-05-10 13:20:06.000000000 +0200 *************** *** 0 **** --- 1,69 ---- + /* Convenience header for conditional use of GNU <libintl.h>. + Copyright (C) 1995-1998, 2000-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + + #ifndef _LIBGETTEXT_H + #define _LIBGETTEXT_H 1 + + /* NLS can be disabled through the configure --disable-nls option. */ + #if ENABLE_NLS + + /* Get declarations of GNU message catalog functions. */ + # include <libintl.h> + + #else + + /* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which + chokes if dcgettext is defined as a macro. So include it now, to make + later inclusions of <locale.h> a NOP. We don't include <libintl.h> + as well because people using "gettext.h" will not include <libintl.h>, + and also including <libintl.h> would fail on SunOS 4, whereas <locale.h> + is OK. */ + #if defined(__sun) + # include <locale.h> + #endif + + /* Disabled NLS. + The casts to 'const char *' serve the purpose of producing warnings + for invalid uses of the value returned from these functions. + On pre-ANSI systems without 'const', the config.h file is supposed to + contain "#define const". */ + # define gettext(Msgid) ((const char *) (Msgid)) + # define dgettext(Domainname, Msgid) ((const char *) (Msgid)) + # define dcgettext(Domainname, Msgid, Category) ((const char *) (Msgid)) + # define ngettext(Msgid1, Msgid2, N) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) + # define dngettext(Domainname, Msgid1, Msgid2, N) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) + # define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) + # define textdomain(Domainname) ((const char *) (Domainname)) + # define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname)) + # define bind_textdomain_codeset(Domainname, Codeset) ((const char *) (Codeset)) + + #endif + + /* A pseudo function call that serves as a marker for the automated + extraction of messages, but does not call gettext(). The run-time + translation is done at a different place in the code. + The argument, String, should be a literal string. Concatenated strings + and other string expressions won't work. + The macro's expansion is not parenthesized, so that it is suitable as + initializer for static 'char[]' or 'const char[]' variables. */ + #define gettext_noop(String) String + + #endif /* _LIBGETTEXT_H */ [-- Attachment #3: Type: text/plain, Size: 143 bytes --] _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: i18n, gettext support 2004-09-04 17:25 ` Bruno Haible @ 2004-09-07 0:13 ` Kevin Ryde 2004-09-07 12:38 ` Bruno Haible 0 siblings, 1 reply; 28+ messages in thread From: Kevin Ryde @ 2004-09-07 0:13 UTC (permalink / raw) Cc: guile-devel, Jan Nieuwenhuizen Bruno Haible <bruno@clisp.org> writes: > > That's your point of view, not mine. I would find it irresponsible if I > were to submit a patch which includes destructive functions that don't > bear a '!' in their name. Well, I guess the conventions for system stuff are described at the start of the posix interface chapter in the manual. I think ! is just meant for changes to scheme level data, not system things. But actually it was the procedure-with-setter I was more concerned about, being almost never used in the core, and in fact a rather controversial concept, as I understand it. > In the GNU 'xgettext' extractor and associated example I will support > whatever API you provide in guile. That'll be (_ "foo") won't it? Being nice and compact, and already used. _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: i18n, gettext support 2004-09-07 0:13 ` Kevin Ryde @ 2004-09-07 12:38 ` Bruno Haible 2004-09-08 1:10 ` Kevin Ryde 0 siblings, 1 reply; 28+ messages in thread From: Bruno Haible @ 2004-09-07 12:38 UTC (permalink / raw) Cc: guile-devel, Jan Nieuwenhuizen Kevin Ryde wrote: > > In the GNU 'xgettext' extractor and associated example I will support > > whatever API you provide in guile. > > That'll be (_ "foo") won't it? Being nice and compact, and already > used. The 'xgettext' extractor will recognize 'gettext', 'ngettext'. I can also make it recognize '_' by default, no problem. However, I don't think the _ should be built-in. Rather, applications will define it differently than libraries: For an application, which typically calls set!-textdomain, a programmer does (define _ gettext) For a library, which must not interfere with the main application, a programmer does (define (_ msgid) (gettext msgid "my-domain")) [I hope Scheme has a package system or environment system that makes it possible to distinguish _ in the application from _ in the library!] Bruno _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: i18n, gettext support 2004-09-07 12:38 ` Bruno Haible @ 2004-09-08 1:10 ` Kevin Ryde 0 siblings, 0 replies; 28+ messages in thread From: Kevin Ryde @ 2004-09-08 1:10 UTC (permalink / raw) Cc: guile-devel, Jan Nieuwenhuizen Bruno Haible <bruno@clisp.org> writes: > > However, I don't think the _ should be built-in. Rather, applications will > define it differently than libraries: Oops, yep. > [I hope Scheme has a package system or environment system that makes it > possible to distinguish _ in the application from _ in the library!] Not as standard, but yes in most, including guile. _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: i18n, gettext support 2004-09-03 1:34 ` Kevin Ryde 2004-09-04 17:25 ` Bruno Haible @ 2004-09-07 8:20 ` Jan Nieuwenhuizen 2004-09-07 14:16 ` Jan Nieuwenhuizen 1 sibling, 1 reply; 28+ messages in thread From: Jan Nieuwenhuizen @ 2004-09-07 8:20 UTC (permalink / raw) Cc: Bruno Haible [-- Attachment #1: Type: text/plain, Size: 317 bytes --] Kevin Ryde writes: > I think these could be a single textdomain func taking an optional > argument. > And I'd call these bindtextdomain, again for similarity to the C > routines they wrap. Ok. In this next iteration, the wrapper functions are [once again] similar to the C functions they wrap. Greetings, Jan. [-- Attachment #2: guile-1.7.1-bh-jcn.diff --] [-- Type: text/plain, Size: 18693 bytes --] ? ABOUT-NLS ? do-diff ? doconf ? libguile/gettext.h ? libguile/i18n.c ? libguile/i18n.h Index: ChangeLog =================================================================== RCS file: /cvsroot/guile/guile/guile-core/ChangeLog,v retrieving revision 1.445 diff -p -u -r1.445 ChangeLog --- ChangeLog 3 Sep 2004 19:45:34 -0000 1.445 +++ ChangeLog 7 Sep 2004 08:14:16 -0000 @@ -1,3 +1,7 @@ +2004-09-02 Bruno Haible <bruno@clisp.org> + + * configure.in: Add AM_GNU_GETTEXT invocation. + 2004-09-03 Stefan Jahn <stefan@lkcc.org> * configure.in (isinf): Let configure find the isinf() function Index: configure.in =================================================================== RCS file: /cvsroot/guile/guile/guile-core/configure.in,v retrieving revision 1.252 diff -p -u -r1.252 configure.in --- configure.in 3 Sep 2004 19:45:35 -0000 1.252 +++ configure.in 7 Sep 2004 08:14:17 -0000 @@ -637,6 +637,9 @@ AC_TRY_LINK([#include <gmp.h>], [mpz_import (0, 0, 0, 0, 0, 0, 0);] , , [AC_MSG_ERROR([At least GNU MP 4.1 is required, see http://swox.com/gmp])]) +dnl i18n tests +AM_GNU_GETTEXT([external], [need-ngettext]) + ### Some systems don't declare some functions. On such systems, we ### need to at least provide our own K&R-style declarations. Index: libguile/ChangeLog =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/ChangeLog,v retrieving revision 1.2140 diff -p -u -r1.2140 ChangeLog --- libguile/ChangeLog 7 Sep 2004 00:34:38 -0000 1.2140 +++ libguile/ChangeLog 7 Sep 2004 08:14:20 -0000 @@ -1,3 +1,23 @@ +2004-09-07 Jan Nieuwenhuizen <janneke@gnu.org> + + * i18n.h, i18n.c (scm_textdomain, scm_bindtextdomain, + scm_bindtextdomain_codeset): Make wrappers similar to C function + they wrap. + +2004-09-04 Jan Nieuwenhuizen <janneke@gnu.org> + Bruno Haible <bruno@clisp.org> + + * i18n.h: New file. + * i18n.c: New file. + * gettext.h: New file, taken from GNU gettext. + * init.c: Include libguile/i18n.h. + (scm_init_guile_1): Add call to scm_init_i18n(). + * Makefile.am (libguile_la_SOURCES): Add i18n.c. + (DOT_X_FILES): Add i18n.x. + (DOT_DOC_FILES): Add i18n.doc. + (libguile_la_LDFLAGS): Add @LTLIBINTL@. + (modinclude_HEADERS): Add i18n.h. + 2004-09-07 Kevin Ryde <user42@zip.com.au> * numbers.c (scm_integer_expt): Reject exponent +/-inf. Index: libguile/Makefile.am =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/Makefile.am,v retrieving revision 1.191 diff -p -u -r1.191 Makefile.am --- libguile/Makefile.am 24 Aug 2004 22:11:35 -0000 1.191 +++ libguile/Makefile.am 7 Sep 2004 08:14:20 -0000 @@ -97,7 +97,7 @@ libguile_la_SOURCES = alist.c arbiters.c gc.c gc-mark.c gc-segment.c gc-malloc.c gc-card.c gc-freelist.c \ gc_os_dep.c gdbint.c gh_data.c gh_eval.c gh_funcs.c gh_init.c \ gh_io.c gh_list.c gh_predicates.c goops.c gsubr.c guardians.c hash.c \ - hashtab.c hooks.c init.c inline.c ioext.c keywords.c \ + hashtab.c hooks.c i18n.c init.c inline.c ioext.c keywords.c \ lang.c list.c \ load.c macros.c mallocs.c modules.c numbers.c objects.c objprop.c \ options.c pairs.c ports.c print.c procprop.c procs.c properties.c \ @@ -113,7 +113,7 @@ DOT_X_FILES = alist.x arbiters.x async.x error.x eval.x evalext.x extensions.x feature.x fluids.x fports.x \ futures.x \ gc.x gc-mark.x gc-segment.x gc-malloc.x gc-card.x goops.x \ - gsubr.x guardians.x hash.x hashtab.x hooks.x init.x ioext.x \ + gsubr.x guardians.x hash.x hashtab.x hooks.x i18n.x init.x ioext.x \ keywords.x lang.x list.x load.x macros.x mallocs.x modules.x \ numbers.x objects.x objprop.x options.x pairs.x ports.x print.x \ procprop.x procs.x properties.x random.x rdelim.x read.x root.x rw.x \ @@ -132,8 +132,8 @@ DOT_DOC_FILES = alist.doc arbiters.doc a extensions.doc feature.doc fluids.doc fports.doc futures.doc \ gc.doc goops.doc \ gsubr.doc gc-mark.doc gc-segment.doc gc-malloc.doc gc-card.doc \ - guardians.doc hash.doc hashtab.doc hooks.doc init.doc ioext.doc \ - keywords.doc lang.doc list.doc load.doc macros.doc \ + guardians.doc hash.doc hashtab.doc hooks.doc i18n.doc init.doc \ + ioext.doc keywords.doc lang.doc list.doc load.doc macros.doc \ mallocs.doc modules.doc numbers.doc objects.doc objprop.doc \ options.doc pairs.doc ports.doc print.doc procprop.doc \ procs.doc properties.doc random.doc rdelim.doc read.doc root.doc rw.doc \ @@ -172,7 +172,7 @@ noinst_HEADERS = convert.i.c \ libguile_la_DEPENDENCIES = @LIBLOBJS@ libguile_la_LIBADD = @LIBLOBJS@ ../libguile-ltdl/libguile-ltdl.la $(THREAD_LIBS_LOCAL) -libguile_la_LDFLAGS = -version-info @LIBGUILE_INTERFACE_CURRENT@:@LIBGUILE_INTERFACE_REVISION@:@LIBGUILE_INTERFACE_AGE@ -export-dynamic -no-undefined +libguile_la_LDFLAGS = @LTLIBINTL@ -version-info @LIBGUILE_INTERFACE_CURRENT@:@LIBGUILE_INTERFACE_REVISION@:@LIBGUILE_INTERFACE_AGE@ -export-dynamic -no-undefined # These are headers visible as <guile/mumble.h> pkginclude_HEADERS = gh.h @@ -187,7 +187,7 @@ modinclude_HEADERS = __scm.h alist.h arb error.h eval.h \ evalext.h extensions.h feature.h filesys.h fluids.h fports.h futures.h \ gc.h gdb_interface.h gdbint.h \ - goops.h gsubr.h guardians.h hash.h hashtab.h hooks.h init.h \ + goops.h gsubr.h guardians.h hash.h hashtab.h hooks.h i18n.h init.h \ inline.h ioext.h \ iselect.h keywords.h lang.h list.h load.h macros.h mallocs.h modules.h \ net_db.h numbers.h objects.h objprop.h options.h pairs.h ports.h posix.h \ Index: libguile/init.c =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/init.c,v retrieving revision 1.159 diff -p -u -r1.159 init.c --- libguile/init.c 24 Aug 2004 22:13:07 -0000 1.159 +++ libguile/init.c 7 Sep 2004 08:14:20 -0000 @@ -63,6 +63,7 @@ #include "libguile/hash.h" #include "libguile/hashtab.h" #include "libguile/hooks.h" +#include "libguile/i18n.h" #include "libguile/iselect.h" #include "libguile/ioext.h" #include "libguile/keywords.h" @@ -477,6 +478,7 @@ scm_init_guile_1 (SCM_STACKITEM *base) scm_init_properties (); scm_init_hooks (); /* Requires smob_prehistory */ scm_init_gc (); /* Requires hooks, async */ + scm_init_i18n (); scm_init_ioext (); scm_init_keywords (); scm_init_list (); --- ../ugh-cvs/libguile/libguile.h 1970-01-01 01:00:00 +0100 +++ libguile/i18n.h 2004-09-07 10:09:45 +0200 @@ -0,0 +1,38 @@ +/* classes: h_files */ + +#ifndef SCM_I18N_H +#define SCM_I18N_H + +/* Copyright (C) 2004 Free Software Foundation, Inc. + * + * 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 "libguile/__scm.h" + +SCM_API SCM scm_gettext (SCM msgid, SCM domainname, SCM category); +SCM_API SCM scm_ngettext (SCM msgid, SCM msgid_plural, SCM n, SCM domainname, SCM category); +SCM_API SCM scm_textdomain (SCM domainname); +SCM_API SCM scm_bindtextdomain (SCM domainname, SCM directory); +SCM_API SCM scm_bindtextdomain_codeset (SCM domainname, SCM encoding); +SCM_API void scm_init_i18n (void); + +#endif /* SCM_I18N_H */ + +/* + Local Variables: + c-file-style: "gnu" + End: +*/ --- ../ugh-cvs/libguile/libguile.c 1970-01-01 01:00:00 +0100 +++ libguile/i18n.c 2004-09-07 10:11:29 +0200 @@ -0,0 +1,266 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + * + * 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 + */ + + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libguile/_scm.h" +#include "libguile/discouraged.h" +#include "libguile/feature.h" +#include "libguile/i18n.h" +#include "libguile/strings.h" +#include "gettext.h" +#include <locale.h> + + +static int +scm_validate_category (SCM category, const char *subr, int pos) +{ + if (scm_is_eq (category, scm_from_int (LC_MESSAGES)) + || scm_is_eq (category, scm_from_int (LC_CTYPE)) + || scm_is_eq (category, scm_from_int (LC_TIME)) + || scm_is_eq (category, scm_from_int (LC_COLLATE)) + || scm_is_eq (category, scm_from_int (LC_MONETARY))) + return scm_to_int (category); + else + scm_wrong_type_arg (subr, pos, category); +} + + +SCM_DEFINE (scm_gettext, "gettext", 1, 2, 0, + (SCM msgid, SCM domain, SCM category), + "Return the translation of @var{msgid} in the message domain " + "@var{domain}. @var{domain} is optional and defaults to the " + "domain set through (textdomain). @var{category} is optional " + "and defaults to LC_MESSAGES.") +#define FUNC_NAME s_scm_gettext +{ + char *c_msgid; + const char *result; + + SCM_VALIDATE_STRING (1, msgid); + c_msgid = scm_to_locale_string (msgid); + if (SCM_UNBNDP (domain)) + { + /* 1 argument case. */ + result = gettext (c_msgid); + } + else + { + char *c_domain; + + SCM_VALIDATE_STRING (2, domain); + c_domain = scm_to_locale_string (domain); + if (SCM_UNBNDP (category)) + { + /* 2 argument case. */ + result = dgettext (c_domain, c_msgid); + } + else + { + /* 3 argument case. */ + int c_category; + + c_category = scm_validate_category (category, FUNC_NAME, 3); + result = dcgettext (c_domain, c_msgid, c_category); + } + free (c_domain); + } + + if (result == c_msgid) + { + free (c_msgid); + return msgid; + } + else + { + free (c_msgid); + return scm_makfrom0str (result); + } +} +#undef FUNC_NAME + + +SCM_DEFINE (scm_ngettext, "ngettext", 3, 2, 0, + (SCM msgid, SCM msgid_plural, SCM n, SCM domain, SCM category), + "Return the translation of @var{msgid}/@var{msgid_plural} in the " + "message domain @var{domain}, with the plural form being chosen " + "appropriately for the number @var{n}. @var{domain} is optional " + "and defaults to the domain set through (textdomain). " + "@var{category} is optional and defaults to LC_MESSAGES.") +#define FUNC_NAME s_scm_ngettext +{ + char *c_msgid; + char *c_msgid_plural; + unsigned long c_n; + const char *result; + + SCM_VALIDATE_STRING (1, msgid); + c_msgid = scm_to_locale_string (msgid); + SCM_VALIDATE_STRING (2, msgid_plural); + c_msgid_plural = scm_to_locale_string (msgid_plural); + SCM_VALIDATE_ULONG_COPY (3, n, c_n); + if (SCM_UNBNDP (domain)) + { + /* 3 argument case. */ + result = ngettext (c_msgid, c_msgid_plural, c_n); + } + else + { + char *c_domain; + + SCM_VALIDATE_STRING (4, domain); + c_domain = scm_to_locale_string (domain); + if (SCM_UNBNDP (category)) + { + /* 4 argument case. */ + result = dngettext (c_domain, c_msgid, c_msgid_plural, c_n); + } + else + { + /* 5 argument case. */ + int c_category; + + c_category = scm_validate_category (category, FUNC_NAME, 5); + result = dcngettext (c_domain, c_msgid, c_msgid_plural, c_n, + c_category); + } + free (c_domain); + } + + if (result == c_msgid) + { + free (c_msgid_plural); + free (c_msgid); + return msgid; + } + else if (result == c_msgid_plural) + { + free (c_msgid_plural); + free (c_msgid); + return msgid_plural; + } + else + { + free (c_msgid_plural); + free (c_msgid); + return scm_makfrom0str (result); + } +} +#undef FUNC_NAME + +SCM_DEFINE (scm_textdomain, "textdomain", 0, 1, 0, + (SCM domainname), + "If optional parameter @var{domainname} is supplied, " + "set the textdomain. " + "Return the textdomain.") +#define FUNC_NAME s_scm_textdomain +{ + char *c_result; + char *c_domain; + + if (SCM_UNBNDP (domainname)) + c_domain = NULL; + else + { + SCM_VALIDATE_STRING (1, domainname); + c_domain = scm_to_locale_string (domainname); + } + c_result = textdomain (c_domain); + if (c_domain != NULL) + free (c_domain); + if (c_result == NULL) + SCM_SYSERROR; + return scm_from_locale_string (c_result); +} +#undef FUNC_NAME + +SCM_DEFINE (scm_bindtextdomain, "bindtextdomain", 1, 1, 0, + (SCM domainname, SCM directory), + "If optional parameter @var{directory} is supplied, " + "set message catalogs to directory @{directory}. " + "Return the directory bound to @var{domainname}.") +#define FUNC_NAME s_scm_bindtextdomain +{ + char *c_domain; + char *c_directory; + char const *c_result; + + SCM_VALIDATE_STRING (1, domainname); + if (SCM_UNBNDP (directory)) + c_directory = NULL; + else + { + SCM_VALIDATE_STRING (2, directory); + c_directory = scm_to_locale_string (directory); + } + c_domain = scm_to_locale_string (domainname); + c_result = bindtextdomain (c_domain, c_directory); + free (c_domain); + if (c_directory != NULL) + free (c_directory); + if (c_result == NULL) + SCM_SYSERROR; + return scm_from_locale_string (c_result); +} +#undef FUNC_NAME + +SCM_DEFINE (scm_bindtextdomain_codeset, "bindtextdomain_codeset", 1, 1, 0, + (SCM domainname, SCM encoding), + "If optional parameter @var{encoding} is supplied, " + "set encoding for message catalogs of @{domainname}. " + "Return the encoding of @var{domainname}.") +#define FUNC_NAME s_scm_bindtextdomain_codeset +{ + char *c_domain; + char *c_encoding; + char const *c_result; + + SCM_VALIDATE_STRING (1, domainname); + if (SCM_UNBNDP (encoding)) + c_encoding = NULL; + else + { + SCM_VALIDATE_STRING (2, encoding); + c_encoding = scm_to_locale_string (encoding); + } + c_domain = scm_to_locale_string (domainname); + c_result = bindtextdomain (c_domain, c_encoding); + free (c_domain); + if (c_encoding != NULL) + free (c_encoding); + if (c_result == NULL) + SCM_SYSERROR; + return scm_from_locale_string (c_result); +} +#undef FUNC_NAME + +void +scm_init_i18n () +{ + scm_add_feature ("i18n"); +#include "libguile/i18n.x" +} + + +/* + Local Variables: + c-file-style: "gnu" + End: +*/ --- ../ugh-cvs/libguile/gettext.h 1970-01-01 01:00:00 +0100 +++ libguile/gettext.h 2004-09-07 09:27:39 +0200 @@ -0,0 +1,69 @@ +/* Convenience header for conditional use of GNU <libintl.h>. + Copyright (C) 1995-1998, 2000-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifndef _LIBGETTEXT_H +#define _LIBGETTEXT_H 1 + +/* NLS can be disabled through the configure --disable-nls option. */ +#if ENABLE_NLS + +/* Get declarations of GNU message catalog functions. */ +# include <libintl.h> + +#else + +/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which + chokes if dcgettext is defined as a macro. So include it now, to make + later inclusions of <locale.h> a NOP. We don't include <libintl.h> + as well because people using "gettext.h" will not include <libintl.h>, + and also including <libintl.h> would fail on SunOS 4, whereas <locale.h> + is OK. */ +#if defined(__sun) +# include <locale.h> +#endif + +/* Disabled NLS. + The casts to 'const char *' serve the purpose of producing warnings + for invalid uses of the value returned from these functions. + On pre-ANSI systems without 'const', the config.h file is supposed to + contain "#define const". */ +# define gettext(Msgid) ((const char *) (Msgid)) +# define dgettext(Domainname, Msgid) ((const char *) (Msgid)) +# define dcgettext(Domainname, Msgid, Category) ((const char *) (Msgid)) +# define ngettext(Msgid1, Msgid2, N) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define dngettext(Domainname, Msgid1, Msgid2, N) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define textdomain(Domainname) ((const char *) (Domainname)) +# define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname)) +# define bind_textdomain_codeset(Domainname, Codeset) ((const char *) (Codeset)) + +#endif + +/* A pseudo function call that serves as a marker for the automated + extraction of messages, but does not call gettext(). The run-time + translation is done at a different place in the code. + The argument, String, should be a literal string. Concatenated strings + and other string expressions won't work. + The macro's expansion is not parenthesized, so that it is suitable as + initializer for static 'char[]' or 'const char[]' variables. */ +#define gettext_noop(String) String + +#endif /* _LIBGETTEXT_H */ [-- Attachment #3: Type: text/plain, Size: 141 bytes --] -- Jan Nieuwenhuizen <janneke@gnu.org> | GNU LilyPond - The music typesetter http://www.xs4all.nl/~jantien | http://www.lilypond.org [-- Attachment #4: Type: text/plain, Size: 143 bytes --] _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: i18n, gettext support 2004-09-07 8:20 ` Jan Nieuwenhuizen @ 2004-09-07 14:16 ` Jan Nieuwenhuizen 2004-09-08 1:15 ` Kevin Ryde 0 siblings, 1 reply; 28+ messages in thread From: Jan Nieuwenhuizen @ 2004-09-07 14:16 UTC (permalink / raw) Cc: Bruno Haible [-- Attachment #1: Type: text/plain, Size: 96 bytes --] Jan Nieuwenhuizen writes: Find a new version with some silly bugs fixed (thanks Bruno). Jan. [-- Attachment #2: guile-1.7.1-bh-jcn-2.diff --] [-- Type: text/plain, Size: 18778 bytes --] ? ABOUT-NLS ? do-diff ? doconf ? libguile/gettext.h ? libguile/i18n.c ? libguile/i18n.h Index: ChangeLog =================================================================== RCS file: /cvsroot/guile/guile/guile-core/ChangeLog,v retrieving revision 1.445 diff -p -u -r1.445 ChangeLog --- ChangeLog 3 Sep 2004 19:45:34 -0000 1.445 +++ ChangeLog 7 Sep 2004 13:19:33 -0000 @@ -1,3 +1,7 @@ +2004-09-02 Bruno Haible <bruno@clisp.org> + + * configure.in: Add AM_GNU_GETTEXT invocation. + 2004-09-03 Stefan Jahn <stefan@lkcc.org> * configure.in (isinf): Let configure find the isinf() function Index: configure.in =================================================================== RCS file: /cvsroot/guile/guile/guile-core/configure.in,v retrieving revision 1.252 diff -p -u -r1.252 configure.in --- configure.in 3 Sep 2004 19:45:35 -0000 1.252 +++ configure.in 7 Sep 2004 13:19:33 -0000 @@ -637,6 +637,9 @@ AC_TRY_LINK([#include <gmp.h>], [mpz_import (0, 0, 0, 0, 0, 0, 0);] , , [AC_MSG_ERROR([At least GNU MP 4.1 is required, see http://swox.com/gmp])]) +dnl i18n tests +AM_GNU_GETTEXT([external], [need-ngettext]) + ### Some systems don't declare some functions. On such systems, we ### need to at least provide our own K&R-style declarations. Index: libguile/ChangeLog =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/ChangeLog,v retrieving revision 1.2140 diff -p -u -r1.2140 ChangeLog --- libguile/ChangeLog 7 Sep 2004 00:34:38 -0000 1.2140 +++ libguile/ChangeLog 7 Sep 2004 13:19:36 -0000 @@ -1,3 +1,23 @@ +2004-09-07 Jan Nieuwenhuizen <janneke@gnu.org> + + * i18n.h, i18n.c (scm_textdomain, scm_bindtextdomain, + scm_bind_textdomain_codeset): Make wrappers similar to C function + they wrap. + +2004-09-04 Jan Nieuwenhuizen <janneke@gnu.org> + Bruno Haible <bruno@clisp.org> + + * i18n.h: New file. + * i18n.c: New file. + * gettext.h: New file, taken from GNU gettext. + * init.c: Include libguile/i18n.h. + (scm_init_guile_1): Add call to scm_init_i18n(). + * Makefile.am (libguile_la_SOURCES): Add i18n.c. + (DOT_X_FILES): Add i18n.x. + (DOT_DOC_FILES): Add i18n.doc. + (libguile_la_LDFLAGS): Add @LTLIBINTL@. + (modinclude_HEADERS): Add i18n.h. + 2004-09-07 Kevin Ryde <user42@zip.com.au> * numbers.c (scm_integer_expt): Reject exponent +/-inf. Index: libguile/Makefile.am =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/Makefile.am,v retrieving revision 1.191 diff -p -u -r1.191 Makefile.am --- libguile/Makefile.am 24 Aug 2004 22:11:35 -0000 1.191 +++ libguile/Makefile.am 7 Sep 2004 13:19:36 -0000 @@ -97,7 +97,7 @@ libguile_la_SOURCES = alist.c arbiters.c gc.c gc-mark.c gc-segment.c gc-malloc.c gc-card.c gc-freelist.c \ gc_os_dep.c gdbint.c gh_data.c gh_eval.c gh_funcs.c gh_init.c \ gh_io.c gh_list.c gh_predicates.c goops.c gsubr.c guardians.c hash.c \ - hashtab.c hooks.c init.c inline.c ioext.c keywords.c \ + hashtab.c hooks.c i18n.c init.c inline.c ioext.c keywords.c \ lang.c list.c \ load.c macros.c mallocs.c modules.c numbers.c objects.c objprop.c \ options.c pairs.c ports.c print.c procprop.c procs.c properties.c \ @@ -113,7 +113,7 @@ DOT_X_FILES = alist.x arbiters.x async.x error.x eval.x evalext.x extensions.x feature.x fluids.x fports.x \ futures.x \ gc.x gc-mark.x gc-segment.x gc-malloc.x gc-card.x goops.x \ - gsubr.x guardians.x hash.x hashtab.x hooks.x init.x ioext.x \ + gsubr.x guardians.x hash.x hashtab.x hooks.x i18n.x init.x ioext.x \ keywords.x lang.x list.x load.x macros.x mallocs.x modules.x \ numbers.x objects.x objprop.x options.x pairs.x ports.x print.x \ procprop.x procs.x properties.x random.x rdelim.x read.x root.x rw.x \ @@ -132,8 +132,8 @@ DOT_DOC_FILES = alist.doc arbiters.doc a extensions.doc feature.doc fluids.doc fports.doc futures.doc \ gc.doc goops.doc \ gsubr.doc gc-mark.doc gc-segment.doc gc-malloc.doc gc-card.doc \ - guardians.doc hash.doc hashtab.doc hooks.doc init.doc ioext.doc \ - keywords.doc lang.doc list.doc load.doc macros.doc \ + guardians.doc hash.doc hashtab.doc hooks.doc i18n.doc init.doc \ + ioext.doc keywords.doc lang.doc list.doc load.doc macros.doc \ mallocs.doc modules.doc numbers.doc objects.doc objprop.doc \ options.doc pairs.doc ports.doc print.doc procprop.doc \ procs.doc properties.doc random.doc rdelim.doc read.doc root.doc rw.doc \ @@ -172,7 +172,7 @@ noinst_HEADERS = convert.i.c \ libguile_la_DEPENDENCIES = @LIBLOBJS@ libguile_la_LIBADD = @LIBLOBJS@ ../libguile-ltdl/libguile-ltdl.la $(THREAD_LIBS_LOCAL) -libguile_la_LDFLAGS = -version-info @LIBGUILE_INTERFACE_CURRENT@:@LIBGUILE_INTERFACE_REVISION@:@LIBGUILE_INTERFACE_AGE@ -export-dynamic -no-undefined +libguile_la_LDFLAGS = @LTLIBINTL@ -version-info @LIBGUILE_INTERFACE_CURRENT@:@LIBGUILE_INTERFACE_REVISION@:@LIBGUILE_INTERFACE_AGE@ -export-dynamic -no-undefined # These are headers visible as <guile/mumble.h> pkginclude_HEADERS = gh.h @@ -187,7 +187,7 @@ modinclude_HEADERS = __scm.h alist.h arb error.h eval.h \ evalext.h extensions.h feature.h filesys.h fluids.h fports.h futures.h \ gc.h gdb_interface.h gdbint.h \ - goops.h gsubr.h guardians.h hash.h hashtab.h hooks.h init.h \ + goops.h gsubr.h guardians.h hash.h hashtab.h hooks.h i18n.h init.h \ inline.h ioext.h \ iselect.h keywords.h lang.h list.h load.h macros.h mallocs.h modules.h \ net_db.h numbers.h objects.h objprop.h options.h pairs.h ports.h posix.h \ Index: libguile/init.c =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/init.c,v retrieving revision 1.159 diff -p -u -r1.159 init.c --- libguile/init.c 24 Aug 2004 22:13:07 -0000 1.159 +++ libguile/init.c 7 Sep 2004 13:19:36 -0000 @@ -63,6 +63,7 @@ #include "libguile/hash.h" #include "libguile/hashtab.h" #include "libguile/hooks.h" +#include "libguile/i18n.h" #include "libguile/iselect.h" #include "libguile/ioext.h" #include "libguile/keywords.h" @@ -477,6 +478,7 @@ scm_init_guile_1 (SCM_STACKITEM *base) scm_init_properties (); scm_init_hooks (); /* Requires smob_prehistory */ scm_init_gc (); /* Requires hooks, async */ + scm_init_i18n (); scm_init_ioext (); scm_init_keywords (); scm_init_list (); --- ../ugh-cvs/libguile/libguile.h 1970-01-01 01:00:00 +0100 +++ libguile/i18n.h 2004-09-07 15:18:07 +0200 @@ -0,0 +1,38 @@ +/* classes: h_files */ + +#ifndef SCM_I18N_H +#define SCM_I18N_H + +/* Copyright (C) 2004 Free Software Foundation, Inc. + * + * 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 "libguile/__scm.h" + +SCM_API SCM scm_gettext (SCM msgid, SCM domainname, SCM category); +SCM_API SCM scm_ngettext (SCM msgid, SCM msgid_plural, SCM n, SCM domainname, SCM category); +SCM_API SCM scm_textdomain (SCM domainname); +SCM_API SCM scm_bindtextdomain (SCM domainname, SCM directory); +SCM_API SCM scm_bind_textdomain_codeset (SCM domainname, SCM encoding); +SCM_API void scm_init_i18n (void); + +#endif /* SCM_I18N_H */ + +/* + Local Variables: + c-file-style: "gnu" + End: +*/ --- ../ugh-cvs/libguile/libguile.c 1970-01-01 01:00:00 +0100 +++ libguile/i18n.c 2004-09-07 15:18:54 +0200 @@ -0,0 +1,270 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + * + * 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 + */ + + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libguile/_scm.h" +#include "libguile/discouraged.h" +#include "libguile/feature.h" +#include "libguile/i18n.h" +#include "libguile/strings.h" +#include "gettext.h" +#include <locale.h> + + +static int +scm_validate_category (SCM category, const char *subr, int pos) +{ + if (scm_is_eq (category, scm_from_int (LC_MESSAGES)) + || scm_is_eq (category, scm_from_int (LC_CTYPE)) + || scm_is_eq (category, scm_from_int (LC_TIME)) + || scm_is_eq (category, scm_from_int (LC_COLLATE)) + || scm_is_eq (category, scm_from_int (LC_MONETARY))) + return scm_to_int (category); + else + scm_wrong_type_arg (subr, pos, category); +} + + +SCM_DEFINE (scm_gettext, "gettext", 1, 2, 0, + (SCM msgid, SCM domain, SCM category), + "Return the translation of @var{msgid} in the message domain " + "@var{domain}. @var{domain} is optional and defaults to the " + "domain set through (textdomain). @var{category} is optional " + "and defaults to LC_MESSAGES.") +#define FUNC_NAME s_scm_gettext +{ + char *c_msgid; + const char *result; + + SCM_VALIDATE_STRING (1, msgid); + c_msgid = scm_to_locale_string (msgid); + if (SCM_UNBNDP (domain)) + { + /* 1 argument case. */ + result = gettext (c_msgid); + } + else + { + char *c_domain; + + SCM_VALIDATE_STRING (2, domain); + c_domain = scm_to_locale_string (domain); + if (SCM_UNBNDP (category)) + { + /* 2 argument case. */ + result = dgettext (c_domain, c_msgid); + } + else + { + /* 3 argument case. */ + int c_category; + + c_category = scm_validate_category (category, FUNC_NAME, 3); + result = dcgettext (c_domain, c_msgid, c_category); + } + free (c_domain); + } + + if (result == c_msgid) + { + free (c_msgid); + return msgid; + } + else + { + free (c_msgid); + return scm_makfrom0str (result); + } +} +#undef FUNC_NAME + + +SCM_DEFINE (scm_ngettext, "ngettext", 3, 2, 0, + (SCM msgid, SCM msgid_plural, SCM n, SCM domain, SCM category), + "Return the translation of @var{msgid}/@var{msgid_plural} in the " + "message domain @var{domain}, with the plural form being chosen " + "appropriately for the number @var{n}. @var{domain} is optional " + "and defaults to the domain set through (textdomain). " + "@var{category} is optional and defaults to LC_MESSAGES.") +#define FUNC_NAME s_scm_ngettext +{ + char *c_msgid; + char *c_msgid_plural; + unsigned long c_n; + const char *result; + + SCM_VALIDATE_STRING (1, msgid); + c_msgid = scm_to_locale_string (msgid); + SCM_VALIDATE_STRING (2, msgid_plural); + c_msgid_plural = scm_to_locale_string (msgid_plural); + SCM_VALIDATE_ULONG_COPY (3, n, c_n); + if (SCM_UNBNDP (domain)) + { + /* 3 argument case. */ + result = ngettext (c_msgid, c_msgid_plural, c_n); + } + else + { + char *c_domain; + + SCM_VALIDATE_STRING (4, domain); + c_domain = scm_to_locale_string (domain); + if (SCM_UNBNDP (category)) + { + /* 4 argument case. */ + result = dngettext (c_domain, c_msgid, c_msgid_plural, c_n); + } + else + { + /* 5 argument case. */ + int c_category; + + c_category = scm_validate_category (category, FUNC_NAME, 5); + result = dcngettext (c_domain, c_msgid, c_msgid_plural, c_n, + c_category); + } + free (c_domain); + } + + if (result == c_msgid) + { + free (c_msgid_plural); + free (c_msgid); + return msgid; + } + else if (result == c_msgid_plural) + { + free (c_msgid_plural); + free (c_msgid); + return msgid_plural; + } + else + { + free (c_msgid_plural); + free (c_msgid); + return scm_makfrom0str (result); + } +} +#undef FUNC_NAME + +SCM_DEFINE (scm_textdomain, "textdomain", 0, 1, 0, + (SCM domainname), + "If optional parameter @var{domainname} is supplied, " + "set the textdomain. " + "Return the textdomain.") +#define FUNC_NAME s_scm_textdomain +{ + char *c_result; + char *c_domain; + + if (SCM_UNBNDP (domainname)) + c_domain = NULL; + else + { + SCM_VALIDATE_STRING (1, domainname); + c_domain = scm_to_locale_string (domainname); + } + c_result = textdomain (c_domain); + if (c_domain != NULL) + free (c_domain); + if (c_result == NULL) + SCM_SYSERROR; + return scm_from_locale_string (c_result); +} +#undef FUNC_NAME + +SCM_DEFINE (scm_bindtextdomain, "bindtextdomain", 1, 1, 0, + (SCM domainname, SCM directory), + "If optional parameter @var{directory} is supplied, " + "set message catalogs to directory @{directory}. " + "Return the directory bound to @var{domainname}.") +#define FUNC_NAME s_scm_bindtextdomain +{ + char *c_domain; + char *c_directory; + char const *c_result; + + SCM_VALIDATE_STRING (1, domainname); + if (SCM_UNBNDP (directory)) + c_directory = NULL; + else + { + SCM_VALIDATE_STRING (2, directory); + c_directory = scm_to_locale_string (directory); + } + c_domain = scm_to_locale_string (domainname); + c_result = bindtextdomain (c_domain, c_directory); + free (c_domain); + if (c_directory != NULL) + free (c_directory); + if (c_result == NULL) + SCM_SYSERROR; + return scm_from_locale_string (c_result); +} +#undef FUNC_NAME + +SCM_DEFINE (scm_bind_textdomain_codeset, "bind-textdomain-codeset", 1, 1, 0, + (SCM domainname, SCM encoding), + "If optional parameter @var{encoding} is supplied, " + "set encoding for message catalogs of @{domainname}. " + "Return the encoding of @var{domainname}.") +#define FUNC_NAME s_scm_bind_textdomain_codeset +{ + char *c_domain; + char *c_encoding; + char const *c_result; + + SCM_VALIDATE_STRING (1, domainname); + if (SCM_UNBNDP (encoding)) + c_encoding = NULL; + else + { + SCM_VALIDATE_STRING (2, encoding); + c_encoding = scm_to_locale_string (encoding); + } + c_domain = scm_to_locale_string (domainname); + c_result = bind_textdomain_codeset (c_domain, c_encoding); + free (c_domain); + if (c_encoding != NULL) + free (c_encoding); + if (c_result == NULL) + { + if (SCM_UNBNDP (encoding)) + return SCM_BOOL_F; + SCM_SYSERROR; + } + return scm_from_locale_string (c_result); +} +#undef FUNC_NAME + +void +scm_init_i18n () +{ + scm_add_feature ("i18n"); +#include "libguile/i18n.x" +} + + +/* + Local Variables: + c-file-style: "gnu" + End: +*/ --- ../ugh-cvs/libguile/gettext.h 1970-01-01 01:00:00 +0100 +++ libguile/gettext.h 2004-09-07 09:27:39 +0200 @@ -0,0 +1,69 @@ +/* Convenience header for conditional use of GNU <libintl.h>. + Copyright (C) 1995-1998, 2000-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifndef _LIBGETTEXT_H +#define _LIBGETTEXT_H 1 + +/* NLS can be disabled through the configure --disable-nls option. */ +#if ENABLE_NLS + +/* Get declarations of GNU message catalog functions. */ +# include <libintl.h> + +#else + +/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which + chokes if dcgettext is defined as a macro. So include it now, to make + later inclusions of <locale.h> a NOP. We don't include <libintl.h> + as well because people using "gettext.h" will not include <libintl.h>, + and also including <libintl.h> would fail on SunOS 4, whereas <locale.h> + is OK. */ +#if defined(__sun) +# include <locale.h> +#endif + +/* Disabled NLS. + The casts to 'const char *' serve the purpose of producing warnings + for invalid uses of the value returned from these functions. + On pre-ANSI systems without 'const', the config.h file is supposed to + contain "#define const". */ +# define gettext(Msgid) ((const char *) (Msgid)) +# define dgettext(Domainname, Msgid) ((const char *) (Msgid)) +# define dcgettext(Domainname, Msgid, Category) ((const char *) (Msgid)) +# define ngettext(Msgid1, Msgid2, N) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define dngettext(Domainname, Msgid1, Msgid2, N) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define textdomain(Domainname) ((const char *) (Domainname)) +# define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname)) +# define bind_textdomain_codeset(Domainname, Codeset) ((const char *) (Codeset)) + +#endif + +/* A pseudo function call that serves as a marker for the automated + extraction of messages, but does not call gettext(). The run-time + translation is done at a different place in the code. + The argument, String, should be a literal string. Concatenated strings + and other string expressions won't work. + The macro's expansion is not parenthesized, so that it is suitable as + initializer for static 'char[]' or 'const char[]' variables. */ +#define gettext_noop(String) String + +#endif /* _LIBGETTEXT_H */ [-- Attachment #3: Type: text/plain, Size: 141 bytes --] -- Jan Nieuwenhuizen <janneke@gnu.org> | GNU LilyPond - The music typesetter http://www.xs4all.nl/~jantien | http://www.lilypond.org [-- Attachment #4: Type: text/plain, Size: 143 bytes --] _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: i18n, gettext support 2004-09-07 14:16 ` Jan Nieuwenhuizen @ 2004-09-08 1:15 ` Kevin Ryde 2004-09-08 8:58 ` Jan Nieuwenhuizen 2004-09-08 10:39 ` Bruno Haible 0 siblings, 2 replies; 28+ messages in thread From: Kevin Ryde @ 2004-09-08 1:15 UTC (permalink / raw) Cc: Bruno Haible, guile-devel Jan Nieuwenhuizen <janneke@gnu.org> writes: > > +static int > +scm_validate_category (SCM category, const char *subr, int pos) Could call that scm_to_lc_category or similar to match the new api style I guess. scm_setlocale (in posix.c) could use it too. _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: i18n, gettext support 2004-09-08 1:15 ` Kevin Ryde @ 2004-09-08 8:58 ` Jan Nieuwenhuizen 2004-09-08 10:39 ` Bruno Haible 1 sibling, 0 replies; 28+ messages in thread From: Jan Nieuwenhuizen @ 2004-09-08 8:58 UTC (permalink / raw) Cc: Bruno Haible [-- Attachment #1: Type: text/plain, Size: 203 bytes --] Kevin Ryde writes: >> +scm_validate_category (SCM category, const char *subr, int pos) > > Could call that scm_to_lc_category [..] > scm_setlocale could use it too. Done. New version attached. Jan. [-- Attachment #2: guile-1.7.1-bh-jcn-3.diff --] [-- Type: text/plain, Size: 21382 bytes --] ? ABOUT-NLS ? do-diff ? doconf ? libguile/gettext.h ? libguile/i18n.c ? libguile/i18n.h Index: ChangeLog =================================================================== RCS file: /cvsroot/guile/guile/guile-core/ChangeLog,v retrieving revision 1.445 diff -p -u -r1.445 ChangeLog --- ChangeLog 3 Sep 2004 19:45:34 -0000 1.445 +++ ChangeLog 8 Sep 2004 08:55:37 -0000 @@ -1,3 +1,7 @@ +2004-09-02 Bruno Haible <bruno@clisp.org> + + * configure.in: Add AM_GNU_GETTEXT invocation. + 2004-09-03 Stefan Jahn <stefan@lkcc.org> * configure.in (isinf): Let configure find the isinf() function Index: configure.in =================================================================== RCS file: /cvsroot/guile/guile/guile-core/configure.in,v retrieving revision 1.252 diff -p -u -r1.252 configure.in --- configure.in 3 Sep 2004 19:45:35 -0000 1.252 +++ configure.in 8 Sep 2004 08:55:37 -0000 @@ -637,6 +637,9 @@ AC_TRY_LINK([#include <gmp.h>], [mpz_import (0, 0, 0, 0, 0, 0, 0);] , , [AC_MSG_ERROR([At least GNU MP 4.1 is required, see http://swox.com/gmp])]) +dnl i18n tests +AM_GNU_GETTEXT([external], [need-ngettext]) + ### Some systems don't declare some functions. On such systems, we ### need to at least provide our own K&R-style declarations. Index: libguile/ChangeLog =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/ChangeLog,v retrieving revision 1.2140 diff -p -u -r1.2140 ChangeLog --- libguile/ChangeLog 7 Sep 2004 00:34:38 -0000 1.2140 +++ libguile/ChangeLog 8 Sep 2004 08:55:40 -0000 @@ -1,3 +1,33 @@ +2004-09-08 Jan Nieuwenhuizen <janneke@gnu.org> + + * posix.c (scm_init_posix): Add LC_PAPER, LC_NAME, LC_ADDRESS, + LC_TELEPHONE, LC_MEASUREMENT, LC_IDENTIFICATION. + + * i18n.c (scm_to_lc_category): New name and export. Support all + LC categories. + + * posix.c (s_scm_setlocale): Use it. + +2004-09-07 Jan Nieuwenhuizen <janneke@gnu.org> + + * i18n.h, i18n.c (scm_textdomain, scm_bindtextdomain, + scm_bind_textdomain_codeset): Make wrappers similar to C function + they wrap. + +2004-09-04 Jan Nieuwenhuizen <janneke@gnu.org> + Bruno Haible <bruno@clisp.org> + + * i18n.h: New file. + * i18n.c: New file. + * gettext.h: New file, taken from GNU gettext. + * init.c: Include libguile/i18n.h. + (scm_init_guile_1): Add call to scm_init_i18n(). + * Makefile.am (libguile_la_SOURCES): Add i18n.c. + (DOT_X_FILES): Add i18n.x. + (DOT_DOC_FILES): Add i18n.doc. + (libguile_la_LDFLAGS): Add @LTLIBINTL@. + (modinclude_HEADERS): Add i18n.h. + 2004-09-07 Kevin Ryde <user42@zip.com.au> * numbers.c (scm_integer_expt): Reject exponent +/-inf. Index: libguile/Makefile.am =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/Makefile.am,v retrieving revision 1.191 diff -p -u -r1.191 Makefile.am --- libguile/Makefile.am 24 Aug 2004 22:11:35 -0000 1.191 +++ libguile/Makefile.am 8 Sep 2004 08:55:41 -0000 @@ -97,7 +97,7 @@ libguile_la_SOURCES = alist.c arbiters.c gc.c gc-mark.c gc-segment.c gc-malloc.c gc-card.c gc-freelist.c \ gc_os_dep.c gdbint.c gh_data.c gh_eval.c gh_funcs.c gh_init.c \ gh_io.c gh_list.c gh_predicates.c goops.c gsubr.c guardians.c hash.c \ - hashtab.c hooks.c init.c inline.c ioext.c keywords.c \ + hashtab.c hooks.c i18n.c init.c inline.c ioext.c keywords.c \ lang.c list.c \ load.c macros.c mallocs.c modules.c numbers.c objects.c objprop.c \ options.c pairs.c ports.c print.c procprop.c procs.c properties.c \ @@ -113,7 +113,7 @@ DOT_X_FILES = alist.x arbiters.x async.x error.x eval.x evalext.x extensions.x feature.x fluids.x fports.x \ futures.x \ gc.x gc-mark.x gc-segment.x gc-malloc.x gc-card.x goops.x \ - gsubr.x guardians.x hash.x hashtab.x hooks.x init.x ioext.x \ + gsubr.x guardians.x hash.x hashtab.x hooks.x i18n.x init.x ioext.x \ keywords.x lang.x list.x load.x macros.x mallocs.x modules.x \ numbers.x objects.x objprop.x options.x pairs.x ports.x print.x \ procprop.x procs.x properties.x random.x rdelim.x read.x root.x rw.x \ @@ -132,8 +132,8 @@ DOT_DOC_FILES = alist.doc arbiters.doc a extensions.doc feature.doc fluids.doc fports.doc futures.doc \ gc.doc goops.doc \ gsubr.doc gc-mark.doc gc-segment.doc gc-malloc.doc gc-card.doc \ - guardians.doc hash.doc hashtab.doc hooks.doc init.doc ioext.doc \ - keywords.doc lang.doc list.doc load.doc macros.doc \ + guardians.doc hash.doc hashtab.doc hooks.doc i18n.doc init.doc \ + ioext.doc keywords.doc lang.doc list.doc load.doc macros.doc \ mallocs.doc modules.doc numbers.doc objects.doc objprop.doc \ options.doc pairs.doc ports.doc print.doc procprop.doc \ procs.doc properties.doc random.doc rdelim.doc read.doc root.doc rw.doc \ @@ -172,7 +172,7 @@ noinst_HEADERS = convert.i.c \ libguile_la_DEPENDENCIES = @LIBLOBJS@ libguile_la_LIBADD = @LIBLOBJS@ ../libguile-ltdl/libguile-ltdl.la $(THREAD_LIBS_LOCAL) -libguile_la_LDFLAGS = -version-info @LIBGUILE_INTERFACE_CURRENT@:@LIBGUILE_INTERFACE_REVISION@:@LIBGUILE_INTERFACE_AGE@ -export-dynamic -no-undefined +libguile_la_LDFLAGS = @LTLIBINTL@ -version-info @LIBGUILE_INTERFACE_CURRENT@:@LIBGUILE_INTERFACE_REVISION@:@LIBGUILE_INTERFACE_AGE@ -export-dynamic -no-undefined # These are headers visible as <guile/mumble.h> pkginclude_HEADERS = gh.h @@ -187,7 +187,7 @@ modinclude_HEADERS = __scm.h alist.h arb error.h eval.h \ evalext.h extensions.h feature.h filesys.h fluids.h fports.h futures.h \ gc.h gdb_interface.h gdbint.h \ - goops.h gsubr.h guardians.h hash.h hashtab.h hooks.h init.h \ + goops.h gsubr.h guardians.h hash.h hashtab.h hooks.h i18n.h init.h \ inline.h ioext.h \ iselect.h keywords.h lang.h list.h load.h macros.h mallocs.h modules.h \ net_db.h numbers.h objects.h objprop.h options.h pairs.h ports.h posix.h \ Index: libguile/init.c =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/init.c,v retrieving revision 1.159 diff -p -u -r1.159 init.c --- libguile/init.c 24 Aug 2004 22:13:07 -0000 1.159 +++ libguile/init.c 8 Sep 2004 08:55:41 -0000 @@ -63,6 +63,7 @@ #include "libguile/hash.h" #include "libguile/hashtab.h" #include "libguile/hooks.h" +#include "libguile/i18n.h" #include "libguile/iselect.h" #include "libguile/ioext.h" #include "libguile/keywords.h" @@ -477,6 +478,7 @@ scm_init_guile_1 (SCM_STACKITEM *base) scm_init_properties (); scm_init_hooks (); /* Requires smob_prehistory */ scm_init_gc (); /* Requires hooks, async */ + scm_init_i18n (); scm_init_ioext (); scm_init_keywords (); scm_init_list (); Index: libguile/posix.c =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/posix.c,v retrieving revision 1.147 diff -p -u -r1.147 posix.c --- libguile/posix.c 7 Sep 2004 00:26:48 -0000 1.147 +++ libguile/posix.c 8 Sep 2004 08:55:41 -0000 @@ -39,6 +39,7 @@ #include "libguile/validate.h" #include "libguile/posix.h" +#include "libguile/i18n.h" \f #ifdef HAVE_STRING_H @@ -1365,7 +1366,7 @@ SCM_DEFINE (scm_setlocale, "setlocale", scm_frame_free (clocale); } - rv = setlocale (scm_to_int (category), clocale); + rv = setlocale (scm_to_lc_category (category, FUNC_NAME, 1), clocale); if (rv == NULL) SCM_SYSERROR; @@ -1929,6 +1930,24 @@ scm_init_posix () #ifdef LC_ALL scm_c_define ("LC_ALL", scm_from_int (LC_ALL)); #endif +#ifdef LC_PAPER + scm_c_define ("LC_PAPER", scm_from_int (LC_PAPER)); +#endif +#ifdef LC_NAME + scm_c_define ("LC_NAME", scm_from_int (LC_NAME)); +#endif +#ifdef LC_ADDRESS + scm_c_define ("LC_ADDRESS", scm_from_int (LC_ADDRESS)); +#endif +#ifdef LC_TELEPHONE + scm_c_define ("LC_TELEPHONE", scm_from_int (LC_TELEPHONE)); +#endif +#ifdef LC_MEASUREMENT + scm_c_define ("LC_MEASUREMENT", scm_from_int (LC_MEASUREMENT)); +#endif +#ifdef LC_IDENTIFICATION + scm_c_define ("LC_IDENTIFICATION", scm_from_int (LC_IDENTIFICATION)); +#endif #ifdef PIPE_BUF scm_c_define ("PIPE_BUF", scm_from_long (PIPE_BUF)); #endif --- ../ugh-cvs/libguile/libguile.h 1970-01-01 01:00:00 +0100 +++ libguile/i18n.h 2004-09-08 09:37:48 +0200 @@ -0,0 +1,39 @@ +/* classes: h_files */ + +#ifndef SCM_I18N_H +#define SCM_I18N_H + +/* Copyright (C) 2004 Free Software Foundation, Inc. + * + * 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 "libguile/__scm.h" + +int scm_to_lc_category (SCM category, const char *subr, int pos); +SCM_API SCM scm_gettext (SCM msgid, SCM domainname, SCM category); +SCM_API SCM scm_ngettext (SCM msgid, SCM msgid_plural, SCM n, SCM domainname, SCM category); +SCM_API SCM scm_textdomain (SCM domainname); +SCM_API SCM scm_bindtextdomain (SCM domainname, SCM directory); +SCM_API SCM scm_bind_textdomain_codeset (SCM domainname, SCM encoding); +SCM_API void scm_init_i18n (void); + +#endif /* SCM_I18N_H */ + +/* + Local Variables: + c-file-style: "gnu" + End: +*/ --- ../ugh-cvs/libguile/libguile.c 1970-01-01 01:00:00 +0100 +++ libguile/i18n.c 2004-09-08 10:50:54 +0200 @@ -0,0 +1,303 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + * + * 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 + */ + + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libguile/_scm.h" +#include "libguile/feature.h" +#include "libguile/i18n.h" +#include "libguile/strings.h" +#include "gettext.h" +#include <locale.h> + + +int +scm_to_lc_category (SCM category, const char *subr, int pos) +{ + if (0 +#ifdef LC_COLLATE + || scm_is_eq (category, scm_from_int (LC_COLLATE)) +#endif +#ifdef LC_CTYPE + || scm_is_eq (category, scm_from_int (LC_CTYPE)) +#endif +#ifdef LC_MONETARY + || scm_is_eq (category, scm_from_int (LC_MONETARY)) +#endif +#ifdef LC_NUMERIC + || scm_is_eq (category, scm_from_int (LC_NUMERIC)) +#endif +#ifdef LC_TIME + || scm_is_eq (category, scm_from_int (LC_TIME)) +#endif +#ifdef LC_MESSAGES + || scm_is_eq (category, scm_from_int (LC_MESSAGES)) +#endif +#ifdef LC_ALL + || scm_is_eq (category, scm_from_int (LC_ALL)) +#endif +#ifdef LC_PAPER + || scm_is_eq (category, scm_from_int (LC_PAPER)) +#endif +#ifdef LC_NAME + || scm_is_eq (category, scm_from_int (LC_NAME)) +#endif +#ifdef LC_ADDRESS + || scm_is_eq (category, scm_from_int (LC_ADDRESS)) +#endif +#ifdef LC_TELEPHONE + || scm_is_eq (category, scm_from_int (LC_TELEPHONE)) +#endif +#ifdef LC_MEASUREMENT + || scm_is_eq (category, scm_from_int (LC_MEASUREMENT)) +#endif +#ifdef LC_IDENTIFICATION + || scm_is_eq (category, scm_from_int (LC_IDENTIFICATION)) +#endif + ) + return scm_to_int (category); + scm_wrong_type_arg (subr, pos, category); +} + +SCM_DEFINE (scm_gettext, "gettext", 1, 2, 0, + (SCM msgid, SCM domain, SCM category), + "Return the translation of @var{msgid} in the message domain " + "@var{domain}. @var{domain} is optional and defaults to the " + "domain set through (textdomain). @var{category} is optional " + "and defaults to LC_MESSAGES.") +#define FUNC_NAME s_scm_gettext +{ + char *c_msgid; + const char *result; + + SCM_VALIDATE_STRING (1, msgid); + c_msgid = scm_to_locale_string (msgid); + if (SCM_UNBNDP (domain)) + { + /* 1 argument case. */ + result = gettext (c_msgid); + } + else + { + char *c_domain; + + SCM_VALIDATE_STRING (2, domain); + c_domain = scm_to_locale_string (domain); + if (SCM_UNBNDP (category)) + { + /* 2 argument case. */ + result = dgettext (c_domain, c_msgid); + } + else + { + /* 3 argument case. */ + int c_category; + + c_category = scm_to_lc_category (category, FUNC_NAME, 3); + result = dcgettext (c_domain, c_msgid, c_category); + } + free (c_domain); + } + + if (result == c_msgid) + { + free (c_msgid); + return msgid; + } + else + { + free (c_msgid); + return scm_from_locale_string (result); + } +} +#undef FUNC_NAME + + +SCM_DEFINE (scm_ngettext, "ngettext", 3, 2, 0, + (SCM msgid, SCM msgid_plural, SCM n, SCM domain, SCM category), + "Return the translation of @var{msgid}/@var{msgid_plural} in the " + "message domain @var{domain}, with the plural form being chosen " + "appropriately for the number @var{n}. @var{domain} is optional " + "and defaults to the domain set through (textdomain). " + "@var{category} is optional and defaults to LC_MESSAGES.") +#define FUNC_NAME s_scm_ngettext +{ + char *c_msgid; + char *c_msgid_plural; + unsigned long c_n; + const char *result; + + SCM_VALIDATE_STRING (1, msgid); + c_msgid = scm_to_locale_string (msgid); + SCM_VALIDATE_STRING (2, msgid_plural); + c_msgid_plural = scm_to_locale_string (msgid_plural); + SCM_VALIDATE_ULONG_COPY (3, n, c_n); + if (SCM_UNBNDP (domain)) + { + /* 3 argument case. */ + result = ngettext (c_msgid, c_msgid_plural, c_n); + } + else + { + char *c_domain; + + SCM_VALIDATE_STRING (4, domain); + c_domain = scm_to_locale_string (domain); + if (SCM_UNBNDP (category)) + { + /* 4 argument case. */ + result = dngettext (c_domain, c_msgid, c_msgid_plural, c_n); + } + else + { + /* 5 argument case. */ + int c_category; + + c_category = scm_to_lc_category (category, FUNC_NAME, 5); + result = dcngettext (c_domain, c_msgid, c_msgid_plural, c_n, + c_category); + } + free (c_domain); + } + + if (result == c_msgid) + { + free (c_msgid_plural); + free (c_msgid); + return msgid; + } + else if (result == c_msgid_plural) + { + free (c_msgid_plural); + free (c_msgid); + return msgid_plural; + } + else + { + free (c_msgid_plural); + free (c_msgid); + return scm_from_locale_string (result); + } +} +#undef FUNC_NAME + +SCM_DEFINE (scm_textdomain, "textdomain", 0, 1, 0, + (SCM domainname), + "If optional parameter @var{domainname} is supplied, " + "set the textdomain. " + "Return the textdomain.") +#define FUNC_NAME s_scm_textdomain +{ + char *c_result; + char *c_domain; + + if (SCM_UNBNDP (domainname)) + c_domain = NULL; + else + { + SCM_VALIDATE_STRING (1, domainname); + c_domain = scm_to_locale_string (domainname); + } + c_result = textdomain (c_domain); + if (c_domain != NULL) + free (c_domain); + if (c_result == NULL) + SCM_SYSERROR; + return scm_from_locale_string (c_result); +} +#undef FUNC_NAME + +SCM_DEFINE (scm_bindtextdomain, "bindtextdomain", 1, 1, 0, + (SCM domainname, SCM directory), + "If optional parameter @var{directory} is supplied, " + "set message catalogs to directory @{directory}. " + "Return the directory bound to @var{domainname}.") +#define FUNC_NAME s_scm_bindtextdomain +{ + char *c_domain; + char *c_directory; + char const *c_result; + + SCM_VALIDATE_STRING (1, domainname); + if (SCM_UNBNDP (directory)) + c_directory = NULL; + else + { + SCM_VALIDATE_STRING (2, directory); + c_directory = scm_to_locale_string (directory); + } + c_domain = scm_to_locale_string (domainname); + c_result = bindtextdomain (c_domain, c_directory); + free (c_domain); + if (c_directory != NULL) + free (c_directory); + if (c_result == NULL) + SCM_SYSERROR; + return scm_from_locale_string (c_result); +} +#undef FUNC_NAME + +SCM_DEFINE (scm_bind_textdomain_codeset, "bind-textdomain-codeset", 1, 1, 0, + (SCM domainname, SCM encoding), + "If optional parameter @var{encoding} is supplied, " + "set encoding for message catalogs of @{domainname}. " + "Return the encoding of @var{domainname}.") +#define FUNC_NAME s_scm_bind_textdomain_codeset +{ + char *c_domain; + char *c_encoding; + char const *c_result; + + SCM_VALIDATE_STRING (1, domainname); + if (SCM_UNBNDP (encoding)) + c_encoding = NULL; + else + { + SCM_VALIDATE_STRING (2, encoding); + c_encoding = scm_to_locale_string (encoding); + } + c_domain = scm_to_locale_string (domainname); + c_result = bind_textdomain_codeset (c_domain, c_encoding); + free (c_domain); + if (c_encoding != NULL) + free (c_encoding); + if (c_result == NULL) + { + if (SCM_UNBNDP (encoding)) + return SCM_BOOL_F; + SCM_SYSERROR; + } + return scm_from_locale_string (c_result); +} +#undef FUNC_NAME + +void +scm_init_i18n () +{ + scm_add_feature ("i18n"); +#include "libguile/i18n.x" +} + + +/* + Local Variables: + c-file-style: "gnu" + End: +*/ --- ../ugh-cvs/libguile/gettext.h 1970-01-01 01:00:00 +0100 +++ libguile/gettext.h 2004-09-07 09:27:39 +0200 @@ -0,0 +1,69 @@ +/* Convenience header for conditional use of GNU <libintl.h>. + Copyright (C) 1995-1998, 2000-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifndef _LIBGETTEXT_H +#define _LIBGETTEXT_H 1 + +/* NLS can be disabled through the configure --disable-nls option. */ +#if ENABLE_NLS + +/* Get declarations of GNU message catalog functions. */ +# include <libintl.h> + +#else + +/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which + chokes if dcgettext is defined as a macro. So include it now, to make + later inclusions of <locale.h> a NOP. We don't include <libintl.h> + as well because people using "gettext.h" will not include <libintl.h>, + and also including <libintl.h> would fail on SunOS 4, whereas <locale.h> + is OK. */ +#if defined(__sun) +# include <locale.h> +#endif + +/* Disabled NLS. + The casts to 'const char *' serve the purpose of producing warnings + for invalid uses of the value returned from these functions. + On pre-ANSI systems without 'const', the config.h file is supposed to + contain "#define const". */ +# define gettext(Msgid) ((const char *) (Msgid)) +# define dgettext(Domainname, Msgid) ((const char *) (Msgid)) +# define dcgettext(Domainname, Msgid, Category) ((const char *) (Msgid)) +# define ngettext(Msgid1, Msgid2, N) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define dngettext(Domainname, Msgid1, Msgid2, N) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define textdomain(Domainname) ((const char *) (Domainname)) +# define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname)) +# define bind_textdomain_codeset(Domainname, Codeset) ((const char *) (Codeset)) + +#endif + +/* A pseudo function call that serves as a marker for the automated + extraction of messages, but does not call gettext(). The run-time + translation is done at a different place in the code. + The argument, String, should be a literal string. Concatenated strings + and other string expressions won't work. + The macro's expansion is not parenthesized, so that it is suitable as + initializer for static 'char[]' or 'const char[]' variables. */ +#define gettext_noop(String) String + +#endif /* _LIBGETTEXT_H */ [-- Attachment #3: Type: text/plain, Size: 141 bytes --] -- Jan Nieuwenhuizen <janneke@gnu.org> | GNU LilyPond - The music typesetter http://www.xs4all.nl/~jantien | http://www.lilypond.org [-- Attachment #4: Type: text/plain, Size: 143 bytes --] _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: i18n, gettext support 2004-09-08 1:15 ` Kevin Ryde 2004-09-08 8:58 ` Jan Nieuwenhuizen @ 2004-09-08 10:39 ` Bruno Haible 2004-09-08 14:37 ` Jan Nieuwenhuizen 2004-09-08 21:53 ` Jan Nieuwenhuizen 1 sibling, 2 replies; 28+ messages in thread From: Bruno Haible @ 2004-09-08 10:39 UTC (permalink / raw) Cc: guile-devel Kevin Ryde wrote: > scm_setlocale (in posix.c) could use it too. setlocale(), however, must accept LC_ALL, which is forbidden in dcgettext() and dcngettext(). Therefore either the test for LC_ALL should be moved to s_scm_setlocale, or the function scm_to_lc_category should take a bool argument telling whether to consider LC_ALL as valid. Bruno _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: i18n, gettext support 2004-09-08 10:39 ` Bruno Haible @ 2004-09-08 14:37 ` Jan Nieuwenhuizen 2004-09-08 16:37 ` Bruno Haible 2004-09-08 21:53 ` Jan Nieuwenhuizen 1 sibling, 1 reply; 28+ messages in thread From: Jan Nieuwenhuizen @ 2004-09-08 14:37 UTC (permalink / raw) Cc: guile-devel Bruno Haible writes: > setlocale(), however, must accept LC_ALL, which is forbidden in dcgettext() > and dcngettext(). Therefore either the test for LC_ALL should be moved to > s_scm_setlocale, or the function scm_to_lc_category should take a bool > argument telling whether to consider LC_ALL as valid. I don't understand. If that's forbidden, d*gettext will tell you that, why add an extra check? Jan. -- Jan Nieuwenhuizen <janneke@gnu.org> | GNU LilyPond - The music typesetter http://www.xs4all.nl/~jantien | http://www.lilypond.org _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: i18n, gettext support 2004-09-08 14:37 ` Jan Nieuwenhuizen @ 2004-09-08 16:37 ` Bruno Haible 0 siblings, 0 replies; 28+ messages in thread From: Bruno Haible @ 2004-09-08 16:37 UTC (permalink / raw) Cc: guile-devel Jan Nieuwenhuizen wrote: > I don't understand. If that's forbidden, d*gettext will tell you that, It's forbidden. dcgettext will not do what people expect when they try to use it. > why add an extra check? In order to tell people that they are writing buggy code when they write (gettext string LC_ALL). There's no difference between LC_ALL and -761 in this respect: both are invalid. Bruno _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: i18n, gettext support 2004-09-08 10:39 ` Bruno Haible 2004-09-08 14:37 ` Jan Nieuwenhuizen @ 2004-09-08 21:53 ` Jan Nieuwenhuizen 2004-09-08 22:45 ` Kevin Ryde 1 sibling, 1 reply; 28+ messages in thread From: Jan Nieuwenhuizen @ 2004-09-08 21:53 UTC (permalink / raw) Cc: Bruno Haible [-- Attachment #1: Type: text/plain, Size: 170 bytes --] Bruno Haible writes: > or the function scm_to_lc_category should take a bool argument > telling whether to consider LC_ALL as valid. Ok, then this should be it. Jan. [-- Attachment #2: guile-1.7.1-bh-jcn-4.diff --] [-- Type: text/plain, Size: 21445 bytes --] ? ABOUT-NLS ? do-diff ? doconf ? libguile/gettext.h ? libguile/i18n.c ? libguile/i18n.h Index: ChangeLog =================================================================== RCS file: /cvsroot/guile/guile/guile-core/ChangeLog,v retrieving revision 1.445 diff -p -u -r1.445 ChangeLog --- ChangeLog 3 Sep 2004 19:45:34 -0000 1.445 +++ ChangeLog 8 Sep 2004 21:47:50 -0000 @@ -1,3 +1,7 @@ +2004-09-02 Bruno Haible <bruno@clisp.org> + + * configure.in: Add AM_GNU_GETTEXT invocation. + 2004-09-03 Stefan Jahn <stefan@lkcc.org> * configure.in (isinf): Let configure find the isinf() function Index: configure.in =================================================================== RCS file: /cvsroot/guile/guile/guile-core/configure.in,v retrieving revision 1.252 diff -p -u -r1.252 configure.in --- configure.in 3 Sep 2004 19:45:35 -0000 1.252 +++ configure.in 8 Sep 2004 21:47:50 -0000 @@ -637,6 +637,9 @@ AC_TRY_LINK([#include <gmp.h>], [mpz_import (0, 0, 0, 0, 0, 0, 0);] , , [AC_MSG_ERROR([At least GNU MP 4.1 is required, see http://swox.com/gmp])]) +dnl i18n tests +AM_GNU_GETTEXT([external], [need-ngettext]) + ### Some systems don't declare some functions. On such systems, we ### need to at least provide our own K&R-style declarations. Index: libguile/ChangeLog =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/ChangeLog,v retrieving revision 1.2140 diff -p -u -r1.2140 ChangeLog --- libguile/ChangeLog 7 Sep 2004 00:34:38 -0000 1.2140 +++ libguile/ChangeLog 8 Sep 2004 21:47:53 -0000 @@ -1,3 +1,33 @@ +2004-09-08 Jan Nieuwenhuizen <janneke@gnu.org> + + * posix.c (scm_init_posix): Add LC_PAPER, LC_NAME, LC_ADDRESS, + LC_TELEPHONE, LC_MEASUREMENT, LC_IDENTIFICATION. + + * i18n.c (scm_to_lc_category): New name and export. Support all + LC categories. + + * posix.c (s_scm_setlocale): Use it. + +2004-09-07 Jan Nieuwenhuizen <janneke@gnu.org> + + * i18n.h, i18n.c (scm_textdomain, scm_bindtextdomain, + scm_bind_textdomain_codeset): Make wrappers similar to C function + they wrap. + +2004-09-04 Jan Nieuwenhuizen <janneke@gnu.org> + Bruno Haible <bruno@clisp.org> + + * i18n.h: New file. + * i18n.c: New file. + * gettext.h: New file, taken from GNU gettext. + * init.c: Include libguile/i18n.h. + (scm_init_guile_1): Add call to scm_init_i18n(). + * Makefile.am (libguile_la_SOURCES): Add i18n.c. + (DOT_X_FILES): Add i18n.x. + (DOT_DOC_FILES): Add i18n.doc. + (libguile_la_LDFLAGS): Add @LTLIBINTL@. + (modinclude_HEADERS): Add i18n.h. + 2004-09-07 Kevin Ryde <user42@zip.com.au> * numbers.c (scm_integer_expt): Reject exponent +/-inf. Index: libguile/Makefile.am =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/Makefile.am,v retrieving revision 1.191 diff -p -u -r1.191 Makefile.am --- libguile/Makefile.am 24 Aug 2004 22:11:35 -0000 1.191 +++ libguile/Makefile.am 8 Sep 2004 21:47:54 -0000 @@ -97,7 +97,7 @@ libguile_la_SOURCES = alist.c arbiters.c gc.c gc-mark.c gc-segment.c gc-malloc.c gc-card.c gc-freelist.c \ gc_os_dep.c gdbint.c gh_data.c gh_eval.c gh_funcs.c gh_init.c \ gh_io.c gh_list.c gh_predicates.c goops.c gsubr.c guardians.c hash.c \ - hashtab.c hooks.c init.c inline.c ioext.c keywords.c \ + hashtab.c hooks.c i18n.c init.c inline.c ioext.c keywords.c \ lang.c list.c \ load.c macros.c mallocs.c modules.c numbers.c objects.c objprop.c \ options.c pairs.c ports.c print.c procprop.c procs.c properties.c \ @@ -113,7 +113,7 @@ DOT_X_FILES = alist.x arbiters.x async.x error.x eval.x evalext.x extensions.x feature.x fluids.x fports.x \ futures.x \ gc.x gc-mark.x gc-segment.x gc-malloc.x gc-card.x goops.x \ - gsubr.x guardians.x hash.x hashtab.x hooks.x init.x ioext.x \ + gsubr.x guardians.x hash.x hashtab.x hooks.x i18n.x init.x ioext.x \ keywords.x lang.x list.x load.x macros.x mallocs.x modules.x \ numbers.x objects.x objprop.x options.x pairs.x ports.x print.x \ procprop.x procs.x properties.x random.x rdelim.x read.x root.x rw.x \ @@ -132,8 +132,8 @@ DOT_DOC_FILES = alist.doc arbiters.doc a extensions.doc feature.doc fluids.doc fports.doc futures.doc \ gc.doc goops.doc \ gsubr.doc gc-mark.doc gc-segment.doc gc-malloc.doc gc-card.doc \ - guardians.doc hash.doc hashtab.doc hooks.doc init.doc ioext.doc \ - keywords.doc lang.doc list.doc load.doc macros.doc \ + guardians.doc hash.doc hashtab.doc hooks.doc i18n.doc init.doc \ + ioext.doc keywords.doc lang.doc list.doc load.doc macros.doc \ mallocs.doc modules.doc numbers.doc objects.doc objprop.doc \ options.doc pairs.doc ports.doc print.doc procprop.doc \ procs.doc properties.doc random.doc rdelim.doc read.doc root.doc rw.doc \ @@ -172,7 +172,7 @@ noinst_HEADERS = convert.i.c \ libguile_la_DEPENDENCIES = @LIBLOBJS@ libguile_la_LIBADD = @LIBLOBJS@ ../libguile-ltdl/libguile-ltdl.la $(THREAD_LIBS_LOCAL) -libguile_la_LDFLAGS = -version-info @LIBGUILE_INTERFACE_CURRENT@:@LIBGUILE_INTERFACE_REVISION@:@LIBGUILE_INTERFACE_AGE@ -export-dynamic -no-undefined +libguile_la_LDFLAGS = @LTLIBINTL@ -version-info @LIBGUILE_INTERFACE_CURRENT@:@LIBGUILE_INTERFACE_REVISION@:@LIBGUILE_INTERFACE_AGE@ -export-dynamic -no-undefined # These are headers visible as <guile/mumble.h> pkginclude_HEADERS = gh.h @@ -187,7 +187,7 @@ modinclude_HEADERS = __scm.h alist.h arb error.h eval.h \ evalext.h extensions.h feature.h filesys.h fluids.h fports.h futures.h \ gc.h gdb_interface.h gdbint.h \ - goops.h gsubr.h guardians.h hash.h hashtab.h hooks.h init.h \ + goops.h gsubr.h guardians.h hash.h hashtab.h hooks.h i18n.h init.h \ inline.h ioext.h \ iselect.h keywords.h lang.h list.h load.h macros.h mallocs.h modules.h \ net_db.h numbers.h objects.h objprop.h options.h pairs.h ports.h posix.h \ Index: libguile/init.c =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/init.c,v retrieving revision 1.159 diff -p -u -r1.159 init.c --- libguile/init.c 24 Aug 2004 22:13:07 -0000 1.159 +++ libguile/init.c 8 Sep 2004 21:47:54 -0000 @@ -63,6 +63,7 @@ #include "libguile/hash.h" #include "libguile/hashtab.h" #include "libguile/hooks.h" +#include "libguile/i18n.h" #include "libguile/iselect.h" #include "libguile/ioext.h" #include "libguile/keywords.h" @@ -477,6 +478,7 @@ scm_init_guile_1 (SCM_STACKITEM *base) scm_init_properties (); scm_init_hooks (); /* Requires smob_prehistory */ scm_init_gc (); /* Requires hooks, async */ + scm_init_i18n (); scm_init_ioext (); scm_init_keywords (); scm_init_list (); Index: libguile/posix.c =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/posix.c,v retrieving revision 1.147 diff -p -u -r1.147 posix.c --- libguile/posix.c 7 Sep 2004 00:26:48 -0000 1.147 +++ libguile/posix.c 8 Sep 2004 21:47:54 -0000 @@ -39,6 +39,7 @@ #include "libguile/validate.h" #include "libguile/posix.h" +#include "libguile/i18n.h" \f #ifdef HAVE_STRING_H @@ -1365,7 +1366,7 @@ SCM_DEFINE (scm_setlocale, "setlocale", scm_frame_free (clocale); } - rv = setlocale (scm_to_int (category), clocale); + rv = setlocale (scm_to_lc_category (category, 1, FUNC_NAME, 1), clocale); if (rv == NULL) SCM_SYSERROR; @@ -1929,6 +1930,24 @@ scm_init_posix () #ifdef LC_ALL scm_c_define ("LC_ALL", scm_from_int (LC_ALL)); #endif +#ifdef LC_PAPER + scm_c_define ("LC_PAPER", scm_from_int (LC_PAPER)); +#endif +#ifdef LC_NAME + scm_c_define ("LC_NAME", scm_from_int (LC_NAME)); +#endif +#ifdef LC_ADDRESS + scm_c_define ("LC_ADDRESS", scm_from_int (LC_ADDRESS)); +#endif +#ifdef LC_TELEPHONE + scm_c_define ("LC_TELEPHONE", scm_from_int (LC_TELEPHONE)); +#endif +#ifdef LC_MEASUREMENT + scm_c_define ("LC_MEASUREMENT", scm_from_int (LC_MEASUREMENT)); +#endif +#ifdef LC_IDENTIFICATION + scm_c_define ("LC_IDENTIFICATION", scm_from_int (LC_IDENTIFICATION)); +#endif #ifdef PIPE_BUF scm_c_define ("PIPE_BUF", scm_from_long (PIPE_BUF)); #endif --- ../ugh-cvs/libguile/libguile.h 1970-01-01 01:00:00 +0100 +++ libguile/i18n.h 2004-09-08 23:44:13 +0200 @@ -0,0 +1,39 @@ +/* classes: h_files */ + +#ifndef SCM_I18N_H +#define SCM_I18N_H + +/* Copyright (C) 2004 Free Software Foundation, Inc. + * + * 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 "libguile/__scm.h" + +int scm_to_lc_category (SCM category, int allow_lc_all, const char *subr, int pos); +SCM_API SCM scm_gettext (SCM msgid, SCM domainname, SCM category); +SCM_API SCM scm_ngettext (SCM msgid, SCM msgid_plural, SCM n, SCM domainname, SCM category); +SCM_API SCM scm_textdomain (SCM domainname); +SCM_API SCM scm_bindtextdomain (SCM domainname, SCM directory); +SCM_API SCM scm_bind_textdomain_codeset (SCM domainname, SCM encoding); +SCM_API void scm_init_i18n (void); + +#endif /* SCM_I18N_H */ + +/* + Local Variables: + c-file-style: "gnu" + End: +*/ --- ../ugh-cvs/libguile/libguile.c 1970-01-01 01:00:00 +0100 +++ libguile/i18n.c 2004-09-08 23:45:35 +0200 @@ -0,0 +1,303 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + * + * 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 + */ + + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libguile/_scm.h" +#include "libguile/feature.h" +#include "libguile/i18n.h" +#include "libguile/strings.h" +#include "gettext.h" +#include <locale.h> + + +int +scm_to_lc_category (SCM category, int allow_lc_all, const char *subr, int pos) +{ + if (0 +#ifdef LC_COLLATE + || scm_is_eq (category, scm_from_int (LC_COLLATE)) +#endif +#ifdef LC_CTYPE + || scm_is_eq (category, scm_from_int (LC_CTYPE)) +#endif +#ifdef LC_MONETARY + || scm_is_eq (category, scm_from_int (LC_MONETARY)) +#endif +#ifdef LC_NUMERIC + || scm_is_eq (category, scm_from_int (LC_NUMERIC)) +#endif +#ifdef LC_TIME + || scm_is_eq (category, scm_from_int (LC_TIME)) +#endif +#ifdef LC_MESSAGES + || scm_is_eq (category, scm_from_int (LC_MESSAGES)) +#endif +#ifdef LC_ALL + || (allow_lc_all && scm_is_eq (category, scm_from_int (LC_ALL))) +#endif +#ifdef LC_PAPER + || scm_is_eq (category, scm_from_int (LC_PAPER)) +#endif +#ifdef LC_NAME + || scm_is_eq (category, scm_from_int (LC_NAME)) +#endif +#ifdef LC_ADDRESS + || scm_is_eq (category, scm_from_int (LC_ADDRESS)) +#endif +#ifdef LC_TELEPHONE + || scm_is_eq (category, scm_from_int (LC_TELEPHONE)) +#endif +#ifdef LC_MEASUREMENT + || scm_is_eq (category, scm_from_int (LC_MEASUREMENT)) +#endif +#ifdef LC_IDENTIFICATION + || scm_is_eq (category, scm_from_int (LC_IDENTIFICATION)) +#endif + ) + return scm_to_int (category); + scm_wrong_type_arg (subr, pos, category); +} + +SCM_DEFINE (scm_gettext, "gettext", 1, 2, 0, + (SCM msgid, SCM domain, SCM category), + "Return the translation of @var{msgid} in the message domain " + "@var{domain}. @var{domain} is optional and defaults to the " + "domain set through (textdomain). @var{category} is optional " + "and defaults to LC_MESSAGES.") +#define FUNC_NAME s_scm_gettext +{ + char *c_msgid; + const char *result; + + SCM_VALIDATE_STRING (1, msgid); + c_msgid = scm_to_locale_string (msgid); + if (SCM_UNBNDP (domain)) + { + /* 1 argument case. */ + result = gettext (c_msgid); + } + else + { + char *c_domain; + + SCM_VALIDATE_STRING (2, domain); + c_domain = scm_to_locale_string (domain); + if (SCM_UNBNDP (category)) + { + /* 2 argument case. */ + result = dgettext (c_domain, c_msgid); + } + else + { + /* 3 argument case. */ + int c_category; + + c_category = scm_to_lc_category (category, 0, FUNC_NAME, 3); + result = dcgettext (c_domain, c_msgid, c_category); + } + free (c_domain); + } + + if (result == c_msgid) + { + free (c_msgid); + return msgid; + } + else + { + free (c_msgid); + return scm_from_locale_string (result); + } +} +#undef FUNC_NAME + + +SCM_DEFINE (scm_ngettext, "ngettext", 3, 2, 0, + (SCM msgid, SCM msgid_plural, SCM n, SCM domain, SCM category), + "Return the translation of @var{msgid}/@var{msgid_plural} in the " + "message domain @var{domain}, with the plural form being chosen " + "appropriately for the number @var{n}. @var{domain} is optional " + "and defaults to the domain set through (textdomain). " + "@var{category} is optional and defaults to LC_MESSAGES.") +#define FUNC_NAME s_scm_ngettext +{ + char *c_msgid; + char *c_msgid_plural; + unsigned long c_n; + const char *result; + + SCM_VALIDATE_STRING (1, msgid); + c_msgid = scm_to_locale_string (msgid); + SCM_VALIDATE_STRING (2, msgid_plural); + c_msgid_plural = scm_to_locale_string (msgid_plural); + SCM_VALIDATE_ULONG_COPY (3, n, c_n); + if (SCM_UNBNDP (domain)) + { + /* 3 argument case. */ + result = ngettext (c_msgid, c_msgid_plural, c_n); + } + else + { + char *c_domain; + + SCM_VALIDATE_STRING (4, domain); + c_domain = scm_to_locale_string (domain); + if (SCM_UNBNDP (category)) + { + /* 4 argument case. */ + result = dngettext (c_domain, c_msgid, c_msgid_plural, c_n); + } + else + { + /* 5 argument case. */ + int c_category; + + c_category = scm_to_lc_category (category, 0, FUNC_NAME, 5); + result = dcngettext (c_domain, c_msgid, c_msgid_plural, c_n, + c_category); + } + free (c_domain); + } + + if (result == c_msgid) + { + free (c_msgid_plural); + free (c_msgid); + return msgid; + } + else if (result == c_msgid_plural) + { + free (c_msgid_plural); + free (c_msgid); + return msgid_plural; + } + else + { + free (c_msgid_plural); + free (c_msgid); + return scm_from_locale_string (result); + } +} +#undef FUNC_NAME + +SCM_DEFINE (scm_textdomain, "textdomain", 0, 1, 0, + (SCM domainname), + "If optional parameter @var{domainname} is supplied, " + "set the textdomain. " + "Return the textdomain.") +#define FUNC_NAME s_scm_textdomain +{ + char *c_result; + char *c_domain; + + if (SCM_UNBNDP (domainname)) + c_domain = NULL; + else + { + SCM_VALIDATE_STRING (1, domainname); + c_domain = scm_to_locale_string (domainname); + } + c_result = textdomain (c_domain); + if (c_domain != NULL) + free (c_domain); + if (c_result == NULL) + SCM_SYSERROR; + return scm_from_locale_string (c_result); +} +#undef FUNC_NAME + +SCM_DEFINE (scm_bindtextdomain, "bindtextdomain", 1, 1, 0, + (SCM domainname, SCM directory), + "If optional parameter @var{directory} is supplied, " + "set message catalogs to directory @{directory}. " + "Return the directory bound to @var{domainname}.") +#define FUNC_NAME s_scm_bindtextdomain +{ + char *c_domain; + char *c_directory; + char const *c_result; + + SCM_VALIDATE_STRING (1, domainname); + if (SCM_UNBNDP (directory)) + c_directory = NULL; + else + { + SCM_VALIDATE_STRING (2, directory); + c_directory = scm_to_locale_string (directory); + } + c_domain = scm_to_locale_string (domainname); + c_result = bindtextdomain (c_domain, c_directory); + free (c_domain); + if (c_directory != NULL) + free (c_directory); + if (c_result == NULL) + SCM_SYSERROR; + return scm_from_locale_string (c_result); +} +#undef FUNC_NAME + +SCM_DEFINE (scm_bind_textdomain_codeset, "bind-textdomain-codeset", 1, 1, 0, + (SCM domainname, SCM encoding), + "If optional parameter @var{encoding} is supplied, " + "set encoding for message catalogs of @{domainname}. " + "Return the encoding of @var{domainname}.") +#define FUNC_NAME s_scm_bind_textdomain_codeset +{ + char *c_domain; + char *c_encoding; + char const *c_result; + + SCM_VALIDATE_STRING (1, domainname); + if (SCM_UNBNDP (encoding)) + c_encoding = NULL; + else + { + SCM_VALIDATE_STRING (2, encoding); + c_encoding = scm_to_locale_string (encoding); + } + c_domain = scm_to_locale_string (domainname); + c_result = bind_textdomain_codeset (c_domain, c_encoding); + free (c_domain); + if (c_encoding != NULL) + free (c_encoding); + if (c_result == NULL) + { + if (SCM_UNBNDP (encoding)) + return SCM_BOOL_F; + SCM_SYSERROR; + } + return scm_from_locale_string (c_result); +} +#undef FUNC_NAME + +void +scm_init_i18n () +{ + scm_add_feature ("i18n"); +#include "libguile/i18n.x" +} + + +/* + Local Variables: + c-file-style: "gnu" + End: +*/ --- ../ugh-cvs/libguile/gettext.h 1970-01-01 01:00:00 +0100 +++ libguile/gettext.h 2004-09-07 09:27:39 +0200 @@ -0,0 +1,69 @@ +/* Convenience header for conditional use of GNU <libintl.h>. + Copyright (C) 1995-1998, 2000-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifndef _LIBGETTEXT_H +#define _LIBGETTEXT_H 1 + +/* NLS can be disabled through the configure --disable-nls option. */ +#if ENABLE_NLS + +/* Get declarations of GNU message catalog functions. */ +# include <libintl.h> + +#else + +/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which + chokes if dcgettext is defined as a macro. So include it now, to make + later inclusions of <locale.h> a NOP. We don't include <libintl.h> + as well because people using "gettext.h" will not include <libintl.h>, + and also including <libintl.h> would fail on SunOS 4, whereas <locale.h> + is OK. */ +#if defined(__sun) +# include <locale.h> +#endif + +/* Disabled NLS. + The casts to 'const char *' serve the purpose of producing warnings + for invalid uses of the value returned from these functions. + On pre-ANSI systems without 'const', the config.h file is supposed to + contain "#define const". */ +# define gettext(Msgid) ((const char *) (Msgid)) +# define dgettext(Domainname, Msgid) ((const char *) (Msgid)) +# define dcgettext(Domainname, Msgid, Category) ((const char *) (Msgid)) +# define ngettext(Msgid1, Msgid2, N) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define dngettext(Domainname, Msgid1, Msgid2, N) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define textdomain(Domainname) ((const char *) (Domainname)) +# define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname)) +# define bind_textdomain_codeset(Domainname, Codeset) ((const char *) (Codeset)) + +#endif + +/* A pseudo function call that serves as a marker for the automated + extraction of messages, but does not call gettext(). The run-time + translation is done at a different place in the code. + The argument, String, should be a literal string. Concatenated strings + and other string expressions won't work. + The macro's expansion is not parenthesized, so that it is suitable as + initializer for static 'char[]' or 'const char[]' variables. */ +#define gettext_noop(String) String + +#endif /* _LIBGETTEXT_H */ [-- Attachment #3: Type: text/plain, Size: 142 bytes --] -- Jan Nieuwenhuizen <janneke@gnu.org> | GNU LilyPond - The music typesetter http://www.xs4all.nl/~jantien | http://www.lilypond.org [-- Attachment #4: Type: text/plain, Size: 143 bytes --] _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: i18n, gettext support 2004-09-08 21:53 ` Jan Nieuwenhuizen @ 2004-09-08 22:45 ` Kevin Ryde 2004-09-08 23:46 ` Jan Nieuwenhuizen 0 siblings, 1 reply; 28+ messages in thread From: Kevin Ryde @ 2004-09-08 22:45 UTC (permalink / raw) Cc: Bruno Haible, guile-devel Jan Nieuwenhuizen <janneke@gnu.org> writes: > > +int > +scm_to_lc_category (SCM category, int allow_lc_all, const char *subr, int pos) The other scm_to_foo's haven't been taking a subr argument. (That's supposed to show up in the backtrace, or something.) > + || scm_is_eq (category, scm_from_int (LC_COLLATE)) Maybe a C "switch", to save some code. _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: i18n, gettext support 2004-09-08 22:45 ` Kevin Ryde @ 2004-09-08 23:46 ` Jan Nieuwenhuizen 2004-09-09 16:25 ` Jan Nieuwenhuizen 0 siblings, 1 reply; 28+ messages in thread From: Jan Nieuwenhuizen @ 2004-09-08 23:46 UTC (permalink / raw) Cc: Bruno Haible [-- Attachment #1: Type: text/plain, Size: 276 bytes --] Kevin Ryde writes: > The other scm_to_foo's haven't been taking a subr argument. (That's > supposed to show up in the backtrace, or something.) Ok, I see. >> + || scm_is_eq (category, scm_from_int (LC_COLLATE)) > Maybe a C "switch", to save some code. Done. Jan. [-- Attachment #2: guile-1.7.1-bh-jcn-5.diff --] [-- Type: text/plain, Size: 20988 bytes --] ? ABOUT-NLS ? do-diff ? doconf ? libguile/gettext.h ? libguile/i18n.c ? libguile/i18n.h Index: ChangeLog =================================================================== RCS file: /cvsroot/guile/guile/guile-core/ChangeLog,v retrieving revision 1.445 diff -p -u -r1.445 ChangeLog --- ChangeLog 3 Sep 2004 19:45:34 -0000 1.445 +++ ChangeLog 8 Sep 2004 23:44:11 -0000 @@ -1,3 +1,7 @@ +2004-09-02 Bruno Haible <bruno@clisp.org> + + * configure.in: Add AM_GNU_GETTEXT invocation. + 2004-09-03 Stefan Jahn <stefan@lkcc.org> * configure.in (isinf): Let configure find the isinf() function Index: configure.in =================================================================== RCS file: /cvsroot/guile/guile/guile-core/configure.in,v retrieving revision 1.252 diff -p -u -r1.252 configure.in --- configure.in 3 Sep 2004 19:45:35 -0000 1.252 +++ configure.in 8 Sep 2004 23:44:12 -0000 @@ -637,6 +637,9 @@ AC_TRY_LINK([#include <gmp.h>], [mpz_import (0, 0, 0, 0, 0, 0, 0);] , , [AC_MSG_ERROR([At least GNU MP 4.1 is required, see http://swox.com/gmp])]) +dnl i18n tests +AM_GNU_GETTEXT([external], [need-ngettext]) + ### Some systems don't declare some functions. On such systems, we ### need to at least provide our own K&R-style declarations. Index: libguile/ChangeLog =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/ChangeLog,v retrieving revision 1.2140 diff -p -u -r1.2140 ChangeLog --- libguile/ChangeLog 7 Sep 2004 00:34:38 -0000 1.2140 +++ libguile/ChangeLog 8 Sep 2004 23:44:17 -0000 @@ -1,3 +1,33 @@ +2004-09-08 Jan Nieuwenhuizen <janneke@gnu.org> + + * posix.c (scm_init_posix): Add LC_PAPER, LC_NAME, LC_ADDRESS, + LC_TELEPHONE, LC_MEASUREMENT, LC_IDENTIFICATION. + + * i18n.c (scm_to_lc_category): New name and export. Support all + LC categories. + + * posix.c (s_scm_setlocale): Use it. + +2004-09-07 Jan Nieuwenhuizen <janneke@gnu.org> + + * i18n.h, i18n.c (scm_textdomain, scm_bindtextdomain, + scm_bind_textdomain_codeset): Make wrappers similar to C function + they wrap. + +2004-09-04 Jan Nieuwenhuizen <janneke@gnu.org> + Bruno Haible <bruno@clisp.org> + + * i18n.h: New file. + * i18n.c: New file. + * gettext.h: New file, taken from GNU gettext. + * init.c: Include libguile/i18n.h. + (scm_init_guile_1): Add call to scm_init_i18n(). + * Makefile.am (libguile_la_SOURCES): Add i18n.c. + (DOT_X_FILES): Add i18n.x. + (DOT_DOC_FILES): Add i18n.doc. + (libguile_la_LDFLAGS): Add @LTLIBINTL@. + (modinclude_HEADERS): Add i18n.h. + 2004-09-07 Kevin Ryde <user42@zip.com.au> * numbers.c (scm_integer_expt): Reject exponent +/-inf. Index: libguile/Makefile.am =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/Makefile.am,v retrieving revision 1.191 diff -p -u -r1.191 Makefile.am --- libguile/Makefile.am 24 Aug 2004 22:11:35 -0000 1.191 +++ libguile/Makefile.am 8 Sep 2004 23:44:17 -0000 @@ -97,7 +97,7 @@ libguile_la_SOURCES = alist.c arbiters.c gc.c gc-mark.c gc-segment.c gc-malloc.c gc-card.c gc-freelist.c \ gc_os_dep.c gdbint.c gh_data.c gh_eval.c gh_funcs.c gh_init.c \ gh_io.c gh_list.c gh_predicates.c goops.c gsubr.c guardians.c hash.c \ - hashtab.c hooks.c init.c inline.c ioext.c keywords.c \ + hashtab.c hooks.c i18n.c init.c inline.c ioext.c keywords.c \ lang.c list.c \ load.c macros.c mallocs.c modules.c numbers.c objects.c objprop.c \ options.c pairs.c ports.c print.c procprop.c procs.c properties.c \ @@ -113,7 +113,7 @@ DOT_X_FILES = alist.x arbiters.x async.x error.x eval.x evalext.x extensions.x feature.x fluids.x fports.x \ futures.x \ gc.x gc-mark.x gc-segment.x gc-malloc.x gc-card.x goops.x \ - gsubr.x guardians.x hash.x hashtab.x hooks.x init.x ioext.x \ + gsubr.x guardians.x hash.x hashtab.x hooks.x i18n.x init.x ioext.x \ keywords.x lang.x list.x load.x macros.x mallocs.x modules.x \ numbers.x objects.x objprop.x options.x pairs.x ports.x print.x \ procprop.x procs.x properties.x random.x rdelim.x read.x root.x rw.x \ @@ -132,8 +132,8 @@ DOT_DOC_FILES = alist.doc arbiters.doc a extensions.doc feature.doc fluids.doc fports.doc futures.doc \ gc.doc goops.doc \ gsubr.doc gc-mark.doc gc-segment.doc gc-malloc.doc gc-card.doc \ - guardians.doc hash.doc hashtab.doc hooks.doc init.doc ioext.doc \ - keywords.doc lang.doc list.doc load.doc macros.doc \ + guardians.doc hash.doc hashtab.doc hooks.doc i18n.doc init.doc \ + ioext.doc keywords.doc lang.doc list.doc load.doc macros.doc \ mallocs.doc modules.doc numbers.doc objects.doc objprop.doc \ options.doc pairs.doc ports.doc print.doc procprop.doc \ procs.doc properties.doc random.doc rdelim.doc read.doc root.doc rw.doc \ @@ -172,7 +172,7 @@ noinst_HEADERS = convert.i.c \ libguile_la_DEPENDENCIES = @LIBLOBJS@ libguile_la_LIBADD = @LIBLOBJS@ ../libguile-ltdl/libguile-ltdl.la $(THREAD_LIBS_LOCAL) -libguile_la_LDFLAGS = -version-info @LIBGUILE_INTERFACE_CURRENT@:@LIBGUILE_INTERFACE_REVISION@:@LIBGUILE_INTERFACE_AGE@ -export-dynamic -no-undefined +libguile_la_LDFLAGS = @LTLIBINTL@ -version-info @LIBGUILE_INTERFACE_CURRENT@:@LIBGUILE_INTERFACE_REVISION@:@LIBGUILE_INTERFACE_AGE@ -export-dynamic -no-undefined # These are headers visible as <guile/mumble.h> pkginclude_HEADERS = gh.h @@ -187,7 +187,7 @@ modinclude_HEADERS = __scm.h alist.h arb error.h eval.h \ evalext.h extensions.h feature.h filesys.h fluids.h fports.h futures.h \ gc.h gdb_interface.h gdbint.h \ - goops.h gsubr.h guardians.h hash.h hashtab.h hooks.h init.h \ + goops.h gsubr.h guardians.h hash.h hashtab.h hooks.h i18n.h init.h \ inline.h ioext.h \ iselect.h keywords.h lang.h list.h load.h macros.h mallocs.h modules.h \ net_db.h numbers.h objects.h objprop.h options.h pairs.h ports.h posix.h \ Index: libguile/init.c =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/init.c,v retrieving revision 1.159 diff -p -u -r1.159 init.c --- libguile/init.c 24 Aug 2004 22:13:07 -0000 1.159 +++ libguile/init.c 8 Sep 2004 23:44:17 -0000 @@ -63,6 +63,7 @@ #include "libguile/hash.h" #include "libguile/hashtab.h" #include "libguile/hooks.h" +#include "libguile/i18n.h" #include "libguile/iselect.h" #include "libguile/ioext.h" #include "libguile/keywords.h" @@ -477,6 +478,7 @@ scm_init_guile_1 (SCM_STACKITEM *base) scm_init_properties (); scm_init_hooks (); /* Requires smob_prehistory */ scm_init_gc (); /* Requires hooks, async */ + scm_init_i18n (); scm_init_ioext (); scm_init_keywords (); scm_init_list (); Index: libguile/posix.c =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/posix.c,v retrieving revision 1.147 diff -p -u -r1.147 posix.c --- libguile/posix.c 7 Sep 2004 00:26:48 -0000 1.147 +++ libguile/posix.c 8 Sep 2004 23:44:17 -0000 @@ -39,6 +39,7 @@ #include "libguile/validate.h" #include "libguile/posix.h" +#include "libguile/i18n.h" \f #ifdef HAVE_STRING_H @@ -1365,7 +1366,7 @@ SCM_DEFINE (scm_setlocale, "setlocale", scm_frame_free (clocale); } - rv = setlocale (scm_to_int (category), clocale); + rv = setlocale (scm_to_lc_category (category, 1, 1), clocale); if (rv == NULL) SCM_SYSERROR; @@ -1929,6 +1930,24 @@ scm_init_posix () #ifdef LC_ALL scm_c_define ("LC_ALL", scm_from_int (LC_ALL)); #endif +#ifdef LC_PAPER + scm_c_define ("LC_PAPER", scm_from_int (LC_PAPER)); +#endif +#ifdef LC_NAME + scm_c_define ("LC_NAME", scm_from_int (LC_NAME)); +#endif +#ifdef LC_ADDRESS + scm_c_define ("LC_ADDRESS", scm_from_int (LC_ADDRESS)); +#endif +#ifdef LC_TELEPHONE + scm_c_define ("LC_TELEPHONE", scm_from_int (LC_TELEPHONE)); +#endif +#ifdef LC_MEASUREMENT + scm_c_define ("LC_MEASUREMENT", scm_from_int (LC_MEASUREMENT)); +#endif +#ifdef LC_IDENTIFICATION + scm_c_define ("LC_IDENTIFICATION", scm_from_int (LC_IDENTIFICATION)); +#endif #ifdef PIPE_BUF scm_c_define ("PIPE_BUF", scm_from_long (PIPE_BUF)); #endif --- ../ugh-cvs/libguile/libguile.h 1970-01-01 01:00:00 +0100 +++ libguile/i18n.h 2004-09-09 01:34:13 +0200 @@ -0,0 +1,39 @@ +/* classes: h_files */ + +#ifndef SCM_I18N_H +#define SCM_I18N_H + +/* Copyright (C) 2004 Free Software Foundation, Inc. + * + * 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 "libguile/__scm.h" + +int scm_to_lc_category (SCM category, int allow_lc_all, int pos); +SCM_API SCM scm_gettext (SCM msgid, SCM domainname, SCM category); +SCM_API SCM scm_ngettext (SCM msgid, SCM msgid_plural, SCM n, SCM domainname, SCM category); +SCM_API SCM scm_textdomain (SCM domainname); +SCM_API SCM scm_bindtextdomain (SCM domainname, SCM directory); +SCM_API SCM scm_bind_textdomain_codeset (SCM domainname, SCM encoding); +SCM_API void scm_init_i18n (void); + +#endif /* SCM_I18N_H */ + +/* + Local Variables: + c-file-style: "gnu" + End: +*/ --- ../ugh-cvs/libguile/libguile.c 1970-01-01 01:00:00 +0100 +++ libguile/i18n.c 2004-09-09 01:37:21 +0200 @@ -0,0 +1,307 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + * + * 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 + */ + + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libguile/_scm.h" +#include "libguile/feature.h" +#include "libguile/i18n.h" +#include "libguile/strings.h" +#include "gettext.h" +#include <locale.h> + + +int +scm_to_lc_category (SCM category, int allow_lc_all, int pos) +{ + int c_category = scm_to_int (category); + switch (c_category) + { +#ifdef LC_CTYPE + case LC_CTYPE: +#endif +#ifdef LC_NUMERIC + case LC_NUMERIC: +#endif +#ifdef LC_COLLATE + case LC_COLLATE: +#endif +#ifdef LC_TIME + case LC_TIME: +#endif +#ifdef LC_MONETARY + case LC_MONETARY: +#endif +#ifdef LC_MESSAGES + case LC_MESSAGES: +#endif +#ifdef LC_PAPER + case LC_PAPER: +#endif +#ifdef LC_NAME + case LC_NAME: +#endif +#ifdef LC_ADDRESS + case LC_ADDRESS: +#endif +#ifdef LC_TELEPHONE + case LC_TELEPHONE: +#endif +#ifdef LC_MEASUREMENT + case LC_MEASUREMENT: +#endif +#ifdef LC_IDENTIFICATION + case LC_IDENTIFICATION: +#endif + return c_category; +#ifdef LC_ALL + case LC_ALL: + if (allow_lc_all) + return c_category; +#endif + } + scm_wrong_type_arg (0, pos, category); +} + +SCM_DEFINE (scm_gettext, "gettext", 1, 2, 0, + (SCM msgid, SCM domain, SCM category), + "Return the translation of @var{msgid} in the message domain " + "@var{domain}. @var{domain} is optional and defaults to the " + "domain set through (textdomain). @var{category} is optional " + "and defaults to LC_MESSAGES.") +#define FUNC_NAME s_scm_gettext +{ + char *c_msgid; + const char *result; + + SCM_VALIDATE_STRING (1, msgid); + c_msgid = scm_to_locale_string (msgid); + if (SCM_UNBNDP (domain)) + { + /* 1 argument case. */ + result = gettext (c_msgid); + } + else + { + char *c_domain; + + SCM_VALIDATE_STRING (2, domain); + c_domain = scm_to_locale_string (domain); + if (SCM_UNBNDP (category)) + { + /* 2 argument case. */ + result = dgettext (c_domain, c_msgid); + } + else + { + /* 3 argument case. */ + int c_category; + + c_category = scm_to_lc_category (category, 0, 3); + result = dcgettext (c_domain, c_msgid, c_category); + } + free (c_domain); + } + + if (result == c_msgid) + { + free (c_msgid); + return msgid; + } + else + { + free (c_msgid); + return scm_from_locale_string (result); + } +} +#undef FUNC_NAME + + +SCM_DEFINE (scm_ngettext, "ngettext", 3, 2, 0, + (SCM msgid, SCM msgid_plural, SCM n, SCM domain, SCM category), + "Return the translation of @var{msgid}/@var{msgid_plural} in the " + "message domain @var{domain}, with the plural form being chosen " + "appropriately for the number @var{n}. @var{domain} is optional " + "and defaults to the domain set through (textdomain). " + "@var{category} is optional and defaults to LC_MESSAGES.") +#define FUNC_NAME s_scm_ngettext +{ + char *c_msgid; + char *c_msgid_plural; + unsigned long c_n; + const char *result; + + SCM_VALIDATE_STRING (1, msgid); + c_msgid = scm_to_locale_string (msgid); + SCM_VALIDATE_STRING (2, msgid_plural); + c_msgid_plural = scm_to_locale_string (msgid_plural); + SCM_VALIDATE_ULONG_COPY (3, n, c_n); + if (SCM_UNBNDP (domain)) + { + /* 3 argument case. */ + result = ngettext (c_msgid, c_msgid_plural, c_n); + } + else + { + char *c_domain; + + SCM_VALIDATE_STRING (4, domain); + c_domain = scm_to_locale_string (domain); + if (SCM_UNBNDP (category)) + { + /* 4 argument case. */ + result = dngettext (c_domain, c_msgid, c_msgid_plural, c_n); + } + else + { + /* 5 argument case. */ + int c_category; + + c_category = scm_to_lc_category (category, 0, 5); + result = dcngettext (c_domain, c_msgid, c_msgid_plural, c_n, + c_category); + } + free (c_domain); + } + + if (result == c_msgid) + { + free (c_msgid_plural); + free (c_msgid); + return msgid; + } + else if (result == c_msgid_plural) + { + free (c_msgid_plural); + free (c_msgid); + return msgid_plural; + } + else + { + free (c_msgid_plural); + free (c_msgid); + return scm_from_locale_string (result); + } +} +#undef FUNC_NAME + +SCM_DEFINE (scm_textdomain, "textdomain", 0, 1, 0, + (SCM domainname), + "If optional parameter @var{domainname} is supplied, " + "set the textdomain. " + "Return the textdomain.") +#define FUNC_NAME s_scm_textdomain +{ + char *c_result; + char *c_domain; + + if (SCM_UNBNDP (domainname)) + c_domain = NULL; + else + { + SCM_VALIDATE_STRING (1, domainname); + c_domain = scm_to_locale_string (domainname); + } + c_result = textdomain (c_domain); + if (c_domain != NULL) + free (c_domain); + if (c_result == NULL) + SCM_SYSERROR; + return scm_from_locale_string (c_result); +} +#undef FUNC_NAME + +SCM_DEFINE (scm_bindtextdomain, "bindtextdomain", 1, 1, 0, + (SCM domainname, SCM directory), + "If optional parameter @var{directory} is supplied, " + "set message catalogs to directory @{directory}. " + "Return the directory bound to @var{domainname}.") +#define FUNC_NAME s_scm_bindtextdomain +{ + char *c_domain; + char *c_directory; + char const *c_result; + + SCM_VALIDATE_STRING (1, domainname); + if (SCM_UNBNDP (directory)) + c_directory = NULL; + else + { + SCM_VALIDATE_STRING (2, directory); + c_directory = scm_to_locale_string (directory); + } + c_domain = scm_to_locale_string (domainname); + c_result = bindtextdomain (c_domain, c_directory); + free (c_domain); + if (c_directory != NULL) + free (c_directory); + if (c_result == NULL) + SCM_SYSERROR; + return scm_from_locale_string (c_result); +} +#undef FUNC_NAME + +SCM_DEFINE (scm_bind_textdomain_codeset, "bind-textdomain-codeset", 1, 1, 0, + (SCM domainname, SCM encoding), + "If optional parameter @var{encoding} is supplied, " + "set encoding for message catalogs of @{domainname}. " + "Return the encoding of @var{domainname}.") +#define FUNC_NAME s_scm_bind_textdomain_codeset +{ + char *c_domain; + char *c_encoding; + char const *c_result; + + SCM_VALIDATE_STRING (1, domainname); + if (SCM_UNBNDP (encoding)) + c_encoding = NULL; + else + { + SCM_VALIDATE_STRING (2, encoding); + c_encoding = scm_to_locale_string (encoding); + } + c_domain = scm_to_locale_string (domainname); + c_result = bind_textdomain_codeset (c_domain, c_encoding); + free (c_domain); + if (c_encoding != NULL) + free (c_encoding); + if (c_result == NULL) + { + if (SCM_UNBNDP (encoding)) + return SCM_BOOL_F; + SCM_SYSERROR; + } + return scm_from_locale_string (c_result); +} +#undef FUNC_NAME + +void +scm_init_i18n () +{ + scm_add_feature ("i18n"); +#include "libguile/i18n.x" +} + + +/* + Local Variables: + c-file-style: "gnu" + End: +*/ --- ../ugh-cvs/libguile/gettext.h 1970-01-01 01:00:00 +0100 +++ libguile/gettext.h 2004-09-07 09:27:39 +0200 @@ -0,0 +1,69 @@ +/* Convenience header for conditional use of GNU <libintl.h>. + Copyright (C) 1995-1998, 2000-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifndef _LIBGETTEXT_H +#define _LIBGETTEXT_H 1 + +/* NLS can be disabled through the configure --disable-nls option. */ +#if ENABLE_NLS + +/* Get declarations of GNU message catalog functions. */ +# include <libintl.h> + +#else + +/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which + chokes if dcgettext is defined as a macro. So include it now, to make + later inclusions of <locale.h> a NOP. We don't include <libintl.h> + as well because people using "gettext.h" will not include <libintl.h>, + and also including <libintl.h> would fail on SunOS 4, whereas <locale.h> + is OK. */ +#if defined(__sun) +# include <locale.h> +#endif + +/* Disabled NLS. + The casts to 'const char *' serve the purpose of producing warnings + for invalid uses of the value returned from these functions. + On pre-ANSI systems without 'const', the config.h file is supposed to + contain "#define const". */ +# define gettext(Msgid) ((const char *) (Msgid)) +# define dgettext(Domainname, Msgid) ((const char *) (Msgid)) +# define dcgettext(Domainname, Msgid, Category) ((const char *) (Msgid)) +# define ngettext(Msgid1, Msgid2, N) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define dngettext(Domainname, Msgid1, Msgid2, N) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define textdomain(Domainname) ((const char *) (Domainname)) +# define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname)) +# define bind_textdomain_codeset(Domainname, Codeset) ((const char *) (Codeset)) + +#endif + +/* A pseudo function call that serves as a marker for the automated + extraction of messages, but does not call gettext(). The run-time + translation is done at a different place in the code. + The argument, String, should be a literal string. Concatenated strings + and other string expressions won't work. + The macro's expansion is not parenthesized, so that it is suitable as + initializer for static 'char[]' or 'const char[]' variables. */ +#define gettext_noop(String) String + +#endif /* _LIBGETTEXT_H */ [-- Attachment #3: Type: text/plain, Size: 141 bytes --] -- Jan Nieuwenhuizen <janneke@gnu.org> | GNU LilyPond - The music typesetter http://www.xs4all.nl/~jantien | http://www.lilypond.org [-- Attachment #4: Type: text/plain, Size: 143 bytes --] _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: i18n, gettext support 2004-09-08 23:46 ` Jan Nieuwenhuizen @ 2004-09-09 16:25 ` Jan Nieuwenhuizen 2004-09-15 11:20 ` Bruno Haible 2004-09-22 0:42 ` Marius Vollmer 0 siblings, 2 replies; 28+ messages in thread From: Jan Nieuwenhuizen @ 2004-09-09 16:25 UTC (permalink / raw) Cc: Bruno Haible [-- Attachment #1: Type: text/plain, Size: 170 bytes --] Jan Nieuwenhuizen writes: New and improved. This version not only compiles, but has also been tested; it should now work even with --disable-nls. Thanks Bruno! Jan. [-- Attachment #2: guile-1.7.1-bh-jcn-6.diff --] [-- Type: text/plain, Size: 21518 bytes --] ? ABOUT-NLS ? do-diff ? doconf ? libguile/gettext.h ? libguile/i18n.c ? libguile/i18n.h Index: ChangeLog =================================================================== RCS file: /cvsroot/guile/guile/guile-core/ChangeLog,v retrieving revision 1.445 diff -p -u -r1.445 ChangeLog --- ChangeLog 3 Sep 2004 19:45:34 -0000 1.445 +++ ChangeLog 9 Sep 2004 15:13:38 -0000 @@ -1,3 +1,7 @@ +2004-09-02 Bruno Haible <bruno@clisp.org> + + * configure.in: Add AM_GNU_GETTEXT invocation. + 2004-09-03 Stefan Jahn <stefan@lkcc.org> * configure.in (isinf): Let configure find the isinf() function Index: configure.in =================================================================== RCS file: /cvsroot/guile/guile/guile-core/configure.in,v retrieving revision 1.252 diff -p -u -r1.252 configure.in --- configure.in 3 Sep 2004 19:45:35 -0000 1.252 +++ configure.in 9 Sep 2004 15:13:38 -0000 @@ -637,6 +637,9 @@ AC_TRY_LINK([#include <gmp.h>], [mpz_import (0, 0, 0, 0, 0, 0, 0);] , , [AC_MSG_ERROR([At least GNU MP 4.1 is required, see http://swox.com/gmp])]) +dnl i18n tests +AM_GNU_GETTEXT([external], [need-ngettext]) + ### Some systems don't declare some functions. On such systems, we ### need to at least provide our own K&R-style declarations. Index: libguile/ChangeLog =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/ChangeLog,v retrieving revision 1.2140 diff -p -u -r1.2140 ChangeLog --- libguile/ChangeLog 7 Sep 2004 00:34:38 -0000 1.2140 +++ libguile/ChangeLog 9 Sep 2004 15:13:41 -0000 @@ -1,3 +1,37 @@ +2004-09-09 Jan Nieuwenhuizen <janneke@gnu.org> + + * i18n.c: Handle --disable-nls (thanks Bruno). + +2004-09-08 Jan Nieuwenhuizen <janneke@gnu.org> + + * posix.c (scm_init_posix): Add LC_PAPER, LC_NAME, LC_ADDRESS, + LC_TELEPHONE, LC_MEASUREMENT, LC_IDENTIFICATION. + + * i18n.c (scm_to_lc_category): New name and export. Support all + LC categories. + + * posix.c (s_scm_setlocale): Use it. + +2004-09-07 Jan Nieuwenhuizen <janneke@gnu.org> + + * i18n.h, i18n.c (scm_textdomain, scm_bindtextdomain, + scm_bind_textdomain_codeset): Make wrappers similar to C function + they wrap. + +2004-09-04 Jan Nieuwenhuizen <janneke@gnu.org> + Bruno Haible <bruno@clisp.org> + + * i18n.h: New file. + * i18n.c: New file. + * gettext.h: New file, taken from GNU gettext. + * init.c: Include libguile/i18n.h. + (scm_init_guile_1): Add call to scm_init_i18n(). + * Makefile.am (libguile_la_SOURCES): Add i18n.c. + (DOT_X_FILES): Add i18n.x. + (DOT_DOC_FILES): Add i18n.doc. + (libguile_la_LDFLAGS): Add @LTLIBINTL@. + (modinclude_HEADERS): Add i18n.h. + 2004-09-07 Kevin Ryde <user42@zip.com.au> * numbers.c (scm_integer_expt): Reject exponent +/-inf. Index: libguile/Makefile.am =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/Makefile.am,v retrieving revision 1.191 diff -p -u -r1.191 Makefile.am --- libguile/Makefile.am 24 Aug 2004 22:11:35 -0000 1.191 +++ libguile/Makefile.am 9 Sep 2004 15:13:41 -0000 @@ -97,7 +97,7 @@ libguile_la_SOURCES = alist.c arbiters.c gc.c gc-mark.c gc-segment.c gc-malloc.c gc-card.c gc-freelist.c \ gc_os_dep.c gdbint.c gh_data.c gh_eval.c gh_funcs.c gh_init.c \ gh_io.c gh_list.c gh_predicates.c goops.c gsubr.c guardians.c hash.c \ - hashtab.c hooks.c init.c inline.c ioext.c keywords.c \ + hashtab.c hooks.c i18n.c init.c inline.c ioext.c keywords.c \ lang.c list.c \ load.c macros.c mallocs.c modules.c numbers.c objects.c objprop.c \ options.c pairs.c ports.c print.c procprop.c procs.c properties.c \ @@ -113,7 +113,7 @@ DOT_X_FILES = alist.x arbiters.x async.x error.x eval.x evalext.x extensions.x feature.x fluids.x fports.x \ futures.x \ gc.x gc-mark.x gc-segment.x gc-malloc.x gc-card.x goops.x \ - gsubr.x guardians.x hash.x hashtab.x hooks.x init.x ioext.x \ + gsubr.x guardians.x hash.x hashtab.x hooks.x i18n.x init.x ioext.x \ keywords.x lang.x list.x load.x macros.x mallocs.x modules.x \ numbers.x objects.x objprop.x options.x pairs.x ports.x print.x \ procprop.x procs.x properties.x random.x rdelim.x read.x root.x rw.x \ @@ -132,8 +132,8 @@ DOT_DOC_FILES = alist.doc arbiters.doc a extensions.doc feature.doc fluids.doc fports.doc futures.doc \ gc.doc goops.doc \ gsubr.doc gc-mark.doc gc-segment.doc gc-malloc.doc gc-card.doc \ - guardians.doc hash.doc hashtab.doc hooks.doc init.doc ioext.doc \ - keywords.doc lang.doc list.doc load.doc macros.doc \ + guardians.doc hash.doc hashtab.doc hooks.doc i18n.doc init.doc \ + ioext.doc keywords.doc lang.doc list.doc load.doc macros.doc \ mallocs.doc modules.doc numbers.doc objects.doc objprop.doc \ options.doc pairs.doc ports.doc print.doc procprop.doc \ procs.doc properties.doc random.doc rdelim.doc read.doc root.doc rw.doc \ @@ -172,7 +172,7 @@ noinst_HEADERS = convert.i.c \ libguile_la_DEPENDENCIES = @LIBLOBJS@ libguile_la_LIBADD = @LIBLOBJS@ ../libguile-ltdl/libguile-ltdl.la $(THREAD_LIBS_LOCAL) -libguile_la_LDFLAGS = -version-info @LIBGUILE_INTERFACE_CURRENT@:@LIBGUILE_INTERFACE_REVISION@:@LIBGUILE_INTERFACE_AGE@ -export-dynamic -no-undefined +libguile_la_LDFLAGS = @LTLIBINTL@ -version-info @LIBGUILE_INTERFACE_CURRENT@:@LIBGUILE_INTERFACE_REVISION@:@LIBGUILE_INTERFACE_AGE@ -export-dynamic -no-undefined # These are headers visible as <guile/mumble.h> pkginclude_HEADERS = gh.h @@ -187,7 +187,7 @@ modinclude_HEADERS = __scm.h alist.h arb error.h eval.h \ evalext.h extensions.h feature.h filesys.h fluids.h fports.h futures.h \ gc.h gdb_interface.h gdbint.h \ - goops.h gsubr.h guardians.h hash.h hashtab.h hooks.h init.h \ + goops.h gsubr.h guardians.h hash.h hashtab.h hooks.h i18n.h init.h \ inline.h ioext.h \ iselect.h keywords.h lang.h list.h load.h macros.h mallocs.h modules.h \ net_db.h numbers.h objects.h objprop.h options.h pairs.h ports.h posix.h \ Index: libguile/init.c =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/init.c,v retrieving revision 1.159 diff -p -u -r1.159 init.c --- libguile/init.c 24 Aug 2004 22:13:07 -0000 1.159 +++ libguile/init.c 9 Sep 2004 15:13:42 -0000 @@ -63,6 +63,7 @@ #include "libguile/hash.h" #include "libguile/hashtab.h" #include "libguile/hooks.h" +#include "libguile/i18n.h" #include "libguile/iselect.h" #include "libguile/ioext.h" #include "libguile/keywords.h" @@ -477,6 +478,7 @@ scm_init_guile_1 (SCM_STACKITEM *base) scm_init_properties (); scm_init_hooks (); /* Requires smob_prehistory */ scm_init_gc (); /* Requires hooks, async */ + scm_init_i18n (); scm_init_ioext (); scm_init_keywords (); scm_init_list (); Index: libguile/posix.c =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/posix.c,v retrieving revision 1.147 diff -p -u -r1.147 posix.c --- libguile/posix.c 7 Sep 2004 00:26:48 -0000 1.147 +++ libguile/posix.c 9 Sep 2004 15:13:42 -0000 @@ -39,6 +39,7 @@ #include "libguile/validate.h" #include "libguile/posix.h" +#include "libguile/i18n.h" \f #ifdef HAVE_STRING_H @@ -1365,7 +1366,7 @@ SCM_DEFINE (scm_setlocale, "setlocale", scm_frame_free (clocale); } - rv = setlocale (scm_to_int (category), clocale); + rv = setlocale (scm_to_lc_category (category, 1, 1), clocale); if (rv == NULL) SCM_SYSERROR; @@ -1929,6 +1930,24 @@ scm_init_posix () #ifdef LC_ALL scm_c_define ("LC_ALL", scm_from_int (LC_ALL)); #endif +#ifdef LC_PAPER + scm_c_define ("LC_PAPER", scm_from_int (LC_PAPER)); +#endif +#ifdef LC_NAME + scm_c_define ("LC_NAME", scm_from_int (LC_NAME)); +#endif +#ifdef LC_ADDRESS + scm_c_define ("LC_ADDRESS", scm_from_int (LC_ADDRESS)); +#endif +#ifdef LC_TELEPHONE + scm_c_define ("LC_TELEPHONE", scm_from_int (LC_TELEPHONE)); +#endif +#ifdef LC_MEASUREMENT + scm_c_define ("LC_MEASUREMENT", scm_from_int (LC_MEASUREMENT)); +#endif +#ifdef LC_IDENTIFICATION + scm_c_define ("LC_IDENTIFICATION", scm_from_int (LC_IDENTIFICATION)); +#endif #ifdef PIPE_BUF scm_c_define ("PIPE_BUF", scm_from_long (PIPE_BUF)); #endif --- ../ugh-cvs/libguile/libguile.h 1970-01-01 01:00:00 +0100 +++ libguile/i18n.h 2004-09-09 01:34:13 +0200 @@ -0,0 +1,39 @@ +/* classes: h_files */ + +#ifndef SCM_I18N_H +#define SCM_I18N_H + +/* Copyright (C) 2004 Free Software Foundation, Inc. + * + * 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 "libguile/__scm.h" + +int scm_to_lc_category (SCM category, int allow_lc_all, int pos); +SCM_API SCM scm_gettext (SCM msgid, SCM domainname, SCM category); +SCM_API SCM scm_ngettext (SCM msgid, SCM msgid_plural, SCM n, SCM domainname, SCM category); +SCM_API SCM scm_textdomain (SCM domainname); +SCM_API SCM scm_bindtextdomain (SCM domainname, SCM directory); +SCM_API SCM scm_bind_textdomain_codeset (SCM domainname, SCM encoding); +SCM_API void scm_init_i18n (void); + +#endif /* SCM_I18N_H */ + +/* + Local Variables: + c-file-style: "gnu" + End: +*/ --- ../ugh-cvs/libguile/libguile.c 1970-01-01 01:00:00 +0100 +++ libguile/i18n.c 2004-09-09 17:00:15 +0200 @@ -0,0 +1,334 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + * + * 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 + */ + + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libguile/_scm.h" +#include "libguile/feature.h" +#include "libguile/i18n.h" +#include "libguile/strings.h" +#include "gettext.h" +#include <locale.h> + + +int +scm_to_lc_category (SCM category, int allow_lc_all, int pos) +{ + int c_category = scm_to_int (category); + switch (c_category) + { +#ifdef LC_CTYPE + case LC_CTYPE: +#endif +#ifdef LC_NUMERIC + case LC_NUMERIC: +#endif +#ifdef LC_COLLATE + case LC_COLLATE: +#endif +#ifdef LC_TIME + case LC_TIME: +#endif +#ifdef LC_MONETARY + case LC_MONETARY: +#endif +#ifdef LC_MESSAGES + case LC_MESSAGES: +#endif +#ifdef LC_PAPER + case LC_PAPER: +#endif +#ifdef LC_NAME + case LC_NAME: +#endif +#ifdef LC_ADDRESS + case LC_ADDRESS: +#endif +#ifdef LC_TELEPHONE + case LC_TELEPHONE: +#endif +#ifdef LC_MEASUREMENT + case LC_MEASUREMENT: +#endif +#ifdef LC_IDENTIFICATION + case LC_IDENTIFICATION: +#endif + return c_category; +#ifdef LC_ALL + case LC_ALL: + if (allow_lc_all) + return c_category; +#endif + } + scm_wrong_type_arg (0, pos, category); +} + +SCM_DEFINE (scm_gettext, "gettext", 1, 2, 0, + (SCM msgid, SCM domain, SCM category), + "Return the translation of @var{msgid} in the message domain " + "@var{domain}. @var{domain} is optional and defaults to the " + "domain set through (textdomain). @var{category} is optional " + "and defaults to LC_MESSAGES.") +#define FUNC_NAME s_scm_gettext +{ + char *c_msgid; + char const *c_result; + + SCM_VALIDATE_STRING (1, msgid); + c_msgid = scm_to_locale_string (msgid); + if (SCM_UNBNDP (domain)) + { + /* 1 argument case. */ + c_result = gettext (c_msgid); + } + else + { + char *c_domain; + + SCM_VALIDATE_STRING (2, domain); + c_domain = scm_to_locale_string (domain); + if (SCM_UNBNDP (category)) + { + /* 2 argument case. */ + c_result = dgettext (c_domain, c_msgid); + } + else + { + /* 3 argument case. */ + int c_category; + + c_category = scm_to_lc_category (category, 0, 3); + c_result = dcgettext (c_domain, c_msgid, c_category); + } + free (c_domain); + } + + if (c_result == c_msgid) + { + free (c_msgid); + return msgid; + } + + free (c_msgid); + return scm_from_locale_string (c_result); +} +#undef FUNC_NAME + + +SCM_DEFINE (scm_ngettext, "ngettext", 3, 2, 0, + (SCM msgid, SCM msgid_plural, SCM n, SCM domain, SCM category), + "Return the translation of @var{msgid}/@var{msgid_plural} in the " + "message domain @var{domain}, with the plural form being chosen " + "appropriately for the number @var{n}. @var{domain} is optional " + "and defaults to the domain set through (textdomain). " + "@var{category} is optional and defaults to LC_MESSAGES.") +#define FUNC_NAME s_scm_ngettext +{ + char *c_msgid; + char *c_msgid_plural; + unsigned long c_n; + const char *result; + + SCM_VALIDATE_STRING (1, msgid); + c_msgid = scm_to_locale_string (msgid); + SCM_VALIDATE_STRING (2, msgid_plural); + c_msgid_plural = scm_to_locale_string (msgid_plural); + SCM_VALIDATE_ULONG_COPY (3, n, c_n); + if (SCM_UNBNDP (domain)) + { + /* 3 argument case. */ + result = ngettext (c_msgid, c_msgid_plural, c_n); + } + else + { + char *c_domain; + + SCM_VALIDATE_STRING (4, domain); + c_domain = scm_to_locale_string (domain); + if (SCM_UNBNDP (category)) + { + /* 4 argument case. */ + result = dngettext (c_domain, c_msgid, c_msgid_plural, c_n); + } + else + { + /* 5 argument case. */ + int c_category; + + c_category = scm_to_lc_category (category, 0, 5); + result = dcngettext (c_domain, c_msgid, c_msgid_plural, c_n, + c_category); + } + free (c_domain); + } + + if (result == c_msgid) + { + free (c_msgid_plural); + free (c_msgid); + return msgid; + } + else if (result == c_msgid_plural) + { + free (c_msgid_plural); + free (c_msgid); + return msgid_plural; + } + + free (c_msgid_plural); + free (c_msgid); + return scm_from_locale_string (result); +} +#undef FUNC_NAME + +SCM_DEFINE (scm_textdomain, "textdomain", 0, 1, 0, + (SCM domainname), + "If optional parameter @var{domainname} is supplied, " + "set the textdomain. " + "Return the textdomain.") +#define FUNC_NAME s_scm_textdomain +{ + char const *c_result; + char *c_domain; + + if (SCM_UNBNDP (domainname)) + c_domain = NULL; + else + { + SCM_VALIDATE_STRING (1, domainname); + c_domain = scm_to_locale_string (domainname); + } + + c_result = textdomain (c_domain); + if (c_result != NULL) + { + SCM result = scm_from_locale_string (c_result); + if (c_domain != NULL) + free (c_domain); + return result; + } + else if (!SCM_UNBNDP (domainname)) + { + if (c_domain != NULL) + free (c_domain); + SCM_SYSERROR; + } + + return SCM_BOOL_F; +} +#undef FUNC_NAME + +SCM_DEFINE (scm_bindtextdomain, "bindtextdomain", 1, 1, 0, + (SCM domainname, SCM directory), + "If optional parameter @var{directory} is supplied, " + "set message catalogs to directory @{directory}. " + "Return the directory bound to @var{domainname}.") +#define FUNC_NAME s_scm_bindtextdomain +{ + char *c_domain; + char *c_directory; + char const *c_result; + + SCM_VALIDATE_STRING (1, domainname); + if (SCM_UNBNDP (directory)) + c_directory = NULL; + else + { + SCM_VALIDATE_STRING (2, directory); + c_directory = scm_to_locale_string (directory); + } + + c_domain = scm_to_locale_string (domainname); + c_result = bindtextdomain (c_domain, c_directory); + free (c_domain); + + if (c_result != NULL) + { + SCM result = scm_from_locale_string (c_result); + if (c_directory != NULL) + free (c_directory); + return result; + } + else if (!SCM_UNBNDP (directory)) + { + if (c_directory != NULL) + free (c_directory); + SCM_SYSERROR; + } + + return SCM_BOOL_F; +} +#undef FUNC_NAME + +SCM_DEFINE (scm_bind_textdomain_codeset, "bind-textdomain-codeset", 1, 1, 0, + (SCM domainname, SCM encoding), + "If optional parameter @var{encoding} is supplied, " + "set encoding for message catalogs of @{domainname}. " + "Return the encoding of @var{domainname}.") +#define FUNC_NAME s_scm_bind_textdomain_codeset +{ + char *c_domain; + char *c_encoding; + char const *c_result; + + SCM_VALIDATE_STRING (1, domainname); + if (SCM_UNBNDP (encoding)) + c_encoding = NULL; + else + { + SCM_VALIDATE_STRING (2, encoding); + c_encoding = scm_to_locale_string (encoding); + } + + c_domain = scm_to_locale_string (domainname); + c_result = bind_textdomain_codeset (c_domain, c_encoding); + free (c_domain); + + if (c_result != NULL) + { + SCM result = scm_from_locale_string (c_result); + if (c_encoding != NULL) + free (c_encoding); + return result; + } + else if (!SCM_UNBNDP (encoding)) + { + if (c_encoding != NULL) + free (c_encoding); + SCM_SYSERROR; + } + + return SCM_BOOL_F; +} +#undef FUNC_NAME + +void +scm_init_i18n () +{ + scm_add_feature ("i18n"); +#include "libguile/i18n.x" +} + + +/* + Local Variables: + c-file-style: "gnu" + End: +*/ --- ../ugh-cvs/libguile/gettext.h 1970-01-01 01:00:00 +0100 +++ libguile/gettext.h 2004-09-07 09:27:39 +0200 @@ -0,0 +1,69 @@ +/* Convenience header for conditional use of GNU <libintl.h>. + Copyright (C) 1995-1998, 2000-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifndef _LIBGETTEXT_H +#define _LIBGETTEXT_H 1 + +/* NLS can be disabled through the configure --disable-nls option. */ +#if ENABLE_NLS + +/* Get declarations of GNU message catalog functions. */ +# include <libintl.h> + +#else + +/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which + chokes if dcgettext is defined as a macro. So include it now, to make + later inclusions of <locale.h> a NOP. We don't include <libintl.h> + as well because people using "gettext.h" will not include <libintl.h>, + and also including <libintl.h> would fail on SunOS 4, whereas <locale.h> + is OK. */ +#if defined(__sun) +# include <locale.h> +#endif + +/* Disabled NLS. + The casts to 'const char *' serve the purpose of producing warnings + for invalid uses of the value returned from these functions. + On pre-ANSI systems without 'const', the config.h file is supposed to + contain "#define const". */ +# define gettext(Msgid) ((const char *) (Msgid)) +# define dgettext(Domainname, Msgid) ((const char *) (Msgid)) +# define dcgettext(Domainname, Msgid, Category) ((const char *) (Msgid)) +# define ngettext(Msgid1, Msgid2, N) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define dngettext(Domainname, Msgid1, Msgid2, N) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define textdomain(Domainname) ((const char *) (Domainname)) +# define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname)) +# define bind_textdomain_codeset(Domainname, Codeset) ((const char *) (Codeset)) + +#endif + +/* A pseudo function call that serves as a marker for the automated + extraction of messages, but does not call gettext(). The run-time + translation is done at a different place in the code. + The argument, String, should be a literal string. Concatenated strings + and other string expressions won't work. + The macro's expansion is not parenthesized, so that it is suitable as + initializer for static 'char[]' or 'const char[]' variables. */ +#define gettext_noop(String) String + +#endif /* _LIBGETTEXT_H */ [-- Attachment #3: Type: text/plain, Size: 141 bytes --] -- Jan Nieuwenhuizen <janneke@gnu.org> | GNU LilyPond - The music typesetter http://www.xs4all.nl/~jantien | http://www.lilypond.org [-- Attachment #4: Type: text/plain, Size: 143 bytes --] _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: i18n, gettext support 2004-09-09 16:25 ` Jan Nieuwenhuizen @ 2004-09-15 11:20 ` Bruno Haible 2004-09-22 0:42 ` Marius Vollmer 1 sibling, 0 replies; 28+ messages in thread From: Bruno Haible @ 2004-09-15 11:20 UTC (permalink / raw) Jan Nieuwenhuizen wrote a week ago: > New and improved. This version not only compiles, but has also been > tested Yes, I too consider it mature for inclusion into guile CVS. Bruno _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: i18n, gettext support 2004-09-09 16:25 ` Jan Nieuwenhuizen 2004-09-15 11:20 ` Bruno Haible @ 2004-09-22 0:42 ` Marius Vollmer 2004-09-22 14:55 ` Bruno Haible 1 sibling, 1 reply; 28+ messages in thread From: Marius Vollmer @ 2004-09-22 0:42 UTC (permalink / raw) Cc: Bruno Haible, guile-devel [-- Attachment #1: Type: text/plain, Size: 552 bytes --] Jan Nieuwenhuizen <janneke@gnu.org> writes: > New and improved. This version not only compiles, but has also been > tested; it should now work even with --disable-nls. Thanks Bruno! I changed it a bit, mostly by using scm_frame_begin and scm_frame_end in i18n.c to manage the temporary strings. Also, there is no need to validate the arguments when using scm_to_local_string. See the patch below. Do you intend scm_to_lc_category to be part of the public API? If so, it will have to be documented, of course. I have made it internal for now. [-- Attachment #2: diff-i18n --] [-- Type: text/plain, Size: 21021 bytes --] Index: ChangeLog =================================================================== RCS file: /cvsroot/guile/guile/guile-core/ChangeLog,v retrieving revision 1.447 diff -u -r1.447 ChangeLog --- ChangeLog 21 Sep 2004 00:10:02 -0000 1.447 +++ ChangeLog 22 Sep 2004 00:38:51 -0000 @@ -1,3 +1,7 @@ +2004-09-22 Marius Vollmer <mvo@zagadka.de> + + * configure.in: Add AM_GNU_GETTEXT invocation. From Bruno Haible. + 2004-09-21 Marius Vollmer <mvo@zagadka.de> * acinclude.m4 (ACX_PTHREAD): New. Index: configure.in =================================================================== RCS file: /cvsroot/guile/guile/guile-core/configure.in,v retrieving revision 1.254 diff -u -r1.254 configure.in --- configure.in 21 Sep 2004 00:09:47 -0000 1.254 +++ configure.in 22 Sep 2004 00:38:55 -0000 @@ -637,6 +637,9 @@ [mpz_import (0, 0, 0, 0, 0, 0, 0);] , , [AC_MSG_ERROR([At least GNU MP 4.1 is required, see http://swox.com/gmp])]) +dnl i18n tests +AM_GNU_GETTEXT([external], [need-ngettext]) + ### Some systems don't declare some functions. On such systems, we ### need to at least provide our own K&R-style declarations. Index: libguile/ChangeLog =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/ChangeLog,v retrieving revision 1.2151 diff -u -r1.2151 ChangeLog --- libguile/ChangeLog 21 Sep 2004 22:05:51 -0000 1.2151 +++ libguile/ChangeLog 22 Sep 2004 00:39:26 -0000 @@ -1,5 +1,35 @@ 2004-09-22 Marius Vollmer <mvo@zagadka.de> + From Jan Nieuwenhuizen <janneke@gnu.org> and Bruno Haible + <bruno@clisp.org>: + + * i18n.c: Handle --disable-nls (thanks Bruno). + + * posix.c (scm_init_posix): Add LC_PAPER, LC_NAME, LC_ADDRESS, + LC_TELEPHONE, LC_MEASUREMENT, LC_IDENTIFICATION. + + * i18n.c (scm_i_to_lc_category): New name and export. Support all + LC categories. + + * posix.c (s_scm_setlocale): Use it. + + * i18n.h, i18n.c (scm_textdomain, scm_bindtextdomain, + scm_bind_textdomain_codeset): Make wrappers similar to C function + they wrap. + + * i18n.h: New file. + * i18n.c: New file. + * gettext.h: New file, taken from GNU gettext. + * init.c: Include libguile/i18n.h. + (scm_init_guile_1): Add call to scm_init_i18n(). + * Makefile.am (libguile_la_SOURCES): Add i18n.c. + (DOT_X_FILES): Add i18n.x. + (DOT_DOC_FILES): Add i18n.doc. + (libguile_la_LDFLAGS): Add @LTLIBINTL@. + (modinclude_HEADERS): Add i18n.h. + +2004-09-22 Marius Vollmer <mvo@zagadka.de> + * eq.c (scm_equal_p): Allow smobs with different flags to be equal by testing for smobs before insisting on equal SCM_CELL_TYPES. Index: libguile/Makefile.am =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/Makefile.am,v retrieving revision 1.192 diff -u -r1.192 Makefile.am --- libguile/Makefile.am 8 Sep 2004 17:15:21 -0000 1.192 +++ libguile/Makefile.am 22 Sep 2004 00:39:27 -0000 @@ -97,7 +97,7 @@ gc.c gc-mark.c gc-segment.c gc-malloc.c gc-card.c gc-freelist.c \ gc_os_dep.c gdbint.c gh_data.c gh_eval.c gh_funcs.c gh_init.c \ gh_io.c gh_list.c gh_predicates.c goops.c gsubr.c guardians.c hash.c \ - hashtab.c hooks.c init.c inline.c ioext.c keywords.c \ + hashtab.c hooks.c i18n.c init.c inline.c ioext.c keywords.c \ lang.c list.c \ load.c macros.c mallocs.c modules.c numbers.c objects.c objprop.c \ options.c pairs.c ports.c print.c procprop.c procs.c properties.c \ @@ -113,7 +113,7 @@ error.x eval.x evalext.x extensions.x feature.x fluids.x fports.x \ futures.x \ gc.x gc-mark.x gc-segment.x gc-malloc.x gc-card.x goops.x \ - gsubr.x guardians.x hash.x hashtab.x hooks.x init.x ioext.x \ + gsubr.x guardians.x hash.x hashtab.x hooks.x i18n.x init.x ioext.x \ keywords.x lang.x list.x load.x macros.x mallocs.x modules.x \ numbers.x objects.x objprop.x options.x pairs.x ports.x print.x \ procprop.x procs.x properties.x random.x rdelim.x read.x root.x rw.x \ @@ -132,8 +132,8 @@ extensions.doc feature.doc fluids.doc fports.doc futures.doc \ gc.doc goops.doc \ gsubr.doc gc-mark.doc gc-segment.doc gc-malloc.doc gc-card.doc \ - guardians.doc hash.doc hashtab.doc hooks.doc init.doc ioext.doc \ - keywords.doc lang.doc list.doc load.doc macros.doc \ + guardians.doc hash.doc hashtab.doc hooks.doc i18n.doc init.doc \ + ioext.doc keywords.doc lang.doc list.doc load.doc macros.doc \ mallocs.doc modules.doc numbers.doc objects.doc objprop.doc \ options.doc pairs.doc ports.doc print.doc procprop.doc \ procs.doc properties.doc random.doc rdelim.doc read.doc root.doc rw.doc \ @@ -172,7 +172,7 @@ libguile_la_DEPENDENCIES = @LIBLOBJS@ libguile_la_LIBADD = @LIBLOBJS@ ../libguile-ltdl/libguile-ltdl.la $(THREAD_LIBS_LOCAL) -libguile_la_LDFLAGS = -version-info @LIBGUILE_INTERFACE_CURRENT@:@LIBGUILE_INTERFACE_REVISION@:@LIBGUILE_INTERFACE_AGE@ -export-dynamic -no-undefined +libguile_la_LDFLAGS = @LTLIBINTL@ -version-info @LIBGUILE_INTERFACE_CURRENT@:@LIBGUILE_INTERFACE_REVISION@:@LIBGUILE_INTERFACE_AGE@ -export-dynamic -no-undefined # These are headers visible as <guile/mumble.h> pkginclude_HEADERS = gh.h @@ -187,7 +187,7 @@ error.h eval.h \ evalext.h extensions.h feature.h filesys.h fluids.h fports.h futures.h \ gc.h gdb_interface.h gdbint.h \ - goops.h gsubr.h guardians.h hash.h hashtab.h hooks.h init.h \ + goops.h gsubr.h guardians.h hash.h hashtab.h hooks.h i18n.h init.h \ inline.h ioext.h \ iselect.h keywords.h lang.h list.h load.h macros.h mallocs.h modules.h \ net_db.h numbers.h objects.h objprop.h options.h pairs.h ports.h posix.h \ Index: libguile/gettext.h =================================================================== RCS file: libguile/gettext.h diff -N libguile/gettext.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ libguile/gettext.h 22 Sep 2004 00:39:28 -0000 @@ -0,0 +1,69 @@ +/* Convenience header for conditional use of GNU <libintl.h>. + Copyright (C) 1995-1998, 2000-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifndef _LIBGETTEXT_H +#define _LIBGETTEXT_H 1 + +/* NLS can be disabled through the configure --disable-nls option. */ +#if ENABLE_NLS + +/* Get declarations of GNU message catalog functions. */ +# include <libintl.h> + +#else + +/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which + chokes if dcgettext is defined as a macro. So include it now, to make + later inclusions of <locale.h> a NOP. We don't include <libintl.h> + as well because people using "gettext.h" will not include <libintl.h>, + and also including <libintl.h> would fail on SunOS 4, whereas <locale.h> + is OK. */ +#if defined(__sun) +# include <locale.h> +#endif + +/* Disabled NLS. + The casts to 'const char *' serve the purpose of producing warnings + for invalid uses of the value returned from these functions. + On pre-ANSI systems without 'const', the config.h file is supposed to + contain "#define const". */ +# define gettext(Msgid) ((const char *) (Msgid)) +# define dgettext(Domainname, Msgid) ((const char *) (Msgid)) +# define dcgettext(Domainname, Msgid, Category) ((const char *) (Msgid)) +# define ngettext(Msgid1, Msgid2, N) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define dngettext(Domainname, Msgid1, Msgid2, N) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define textdomain(Domainname) ((const char *) (Domainname)) +# define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname)) +# define bind_textdomain_codeset(Domainname, Codeset) ((const char *) (Codeset)) + +#endif + +/* A pseudo function call that serves as a marker for the automated + extraction of messages, but does not call gettext(). The run-time + translation is done at a different place in the code. + The argument, String, should be a literal string. Concatenated strings + and other string expressions won't work. + The macro's expansion is not parenthesized, so that it is suitable as + initializer for static 'char[]' or 'const char[]' variables. */ +#define gettext_noop(String) String + +#endif /* _LIBGETTEXT_H */ Index: libguile/i18n.c =================================================================== RCS file: libguile/i18n.c diff -N libguile/i18n.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ libguile/i18n.c 22 Sep 2004 00:39:28 -0000 @@ -0,0 +1,327 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + * + * 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 + */ + + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libguile/_scm.h" +#include "libguile/feature.h" +#include "libguile/i18n.h" +#include "libguile/strings.h" +#include "libguile/dynwind.h" + +#include "gettext.h" +#include <locale.h> + + +int +scm_i_to_lc_category (SCM category, int allow_lc_all) +{ + int c_category = scm_to_int (category); + switch (c_category) + { +#ifdef LC_CTYPE + case LC_CTYPE: +#endif +#ifdef LC_NUMERIC + case LC_NUMERIC: +#endif +#ifdef LC_COLLATE + case LC_COLLATE: +#endif +#ifdef LC_TIME + case LC_TIME: +#endif +#ifdef LC_MONETARY + case LC_MONETARY: +#endif +#ifdef LC_MESSAGES + case LC_MESSAGES: +#endif +#ifdef LC_PAPER + case LC_PAPER: +#endif +#ifdef LC_NAME + case LC_NAME: +#endif +#ifdef LC_ADDRESS + case LC_ADDRESS: +#endif +#ifdef LC_TELEPHONE + case LC_TELEPHONE: +#endif +#ifdef LC_MEASUREMENT + case LC_MEASUREMENT: +#endif +#ifdef LC_IDENTIFICATION + case LC_IDENTIFICATION: +#endif + return c_category; +#ifdef LC_ALL + case LC_ALL: + if (allow_lc_all) + return c_category; +#endif + } + scm_wrong_type_arg (0, 0, category); +} + +SCM_DEFINE (scm_gettext, "gettext", 1, 2, 0, + (SCM msgid, SCM domain, SCM category), + "Return the translation of @var{msgid} in the message domain " + "@var{domain}. @var{domain} is optional and defaults to the " + "domain set through (textdomain). @var{category} is optional " + "and defaults to LC_MESSAGES.") +#define FUNC_NAME s_scm_gettext +{ + char *c_msgid; + char const *c_result; + SCM result; + + scm_frame_begin (0); + + c_msgid = scm_to_locale_string (msgid); + scm_frame_free (c_msgid); + + if (SCM_UNBNDP (domain)) + { + /* 1 argument case. */ + c_result = gettext (c_msgid); + } + else + { + char *c_domain; + + c_domain = scm_to_locale_string (domain); + scm_frame_free (c_domain); + + if (SCM_UNBNDP (category)) + { + /* 2 argument case. */ + c_result = dgettext (c_domain, c_msgid); + } + else + { + /* 3 argument case. */ + int c_category; + + c_category = scm_i_to_lc_category (category, 0); + c_result = dcgettext (c_domain, c_msgid, c_category); + } + } + + if (c_result == c_msgid) + result = msgid; + else + result = scm_from_locale_string (c_result); + + scm_frame_end (); + return result; +} +#undef FUNC_NAME + + +SCM_DEFINE (scm_ngettext, "ngettext", 3, 2, 0, + (SCM msgid, SCM msgid_plural, SCM n, SCM domain, SCM category), + "Return the translation of @var{msgid}/@var{msgid_plural} in the " + "message domain @var{domain}, with the plural form being chosen " + "appropriately for the number @var{n}. @var{domain} is optional " + "and defaults to the domain set through (textdomain). " + "@var{category} is optional and defaults to LC_MESSAGES.") +#define FUNC_NAME s_scm_ngettext +{ + char *c_msgid; + char *c_msgid_plural; + unsigned long c_n; + const char *c_result; + SCM result; + + scm_frame_begin (0); + + c_msgid = scm_to_locale_string (msgid); + scm_frame_free (c_msgid); + + c_msgid_plural = scm_to_locale_string (msgid_plural); + scm_frame_free (c_msgid_plural); + + c_n = scm_to_ulong (n); + + if (SCM_UNBNDP (domain)) + { + /* 3 argument case. */ + c_result = ngettext (c_msgid, c_msgid_plural, c_n); + } + else + { + char *c_domain; + + c_domain = scm_to_locale_string (domain); + scm_frame_free (c_domain); + + if (SCM_UNBNDP (category)) + { + /* 4 argument case. */ + c_result = dngettext (c_domain, c_msgid, c_msgid_plural, c_n); + } + else + { + /* 5 argument case. */ + int c_category; + + c_category = scm_i_to_lc_category (category, 0); + c_result = dcngettext (c_domain, c_msgid, c_msgid_plural, c_n, + c_category); + } + } + + if (c_result == c_msgid) + result = msgid; + else if (c_result == c_msgid_plural) + result = msgid_plural; + else + result = scm_from_locale_string (c_result); + + scm_frame_end (); + return result; +} +#undef FUNC_NAME + +SCM_DEFINE (scm_textdomain, "textdomain", 0, 1, 0, + (SCM domainname), + "If optional parameter @var{domainname} is supplied, " + "set the textdomain. " + "Return the textdomain.") +#define FUNC_NAME s_scm_textdomain +{ + char const *c_result; + char *c_domain; + SCM result = SCM_BOOL_F; + + scm_frame_begin (0); + + if (SCM_UNBNDP (domainname)) + c_domain = NULL; + else + { + c_domain = scm_to_locale_string (domainname); + scm_frame_free (c_domain); + } + + c_result = textdomain (c_domain); + if (c_result != NULL) + result = scm_from_locale_string (c_result); + else if (!SCM_UNBNDP (domainname)) + SCM_SYSERROR; + + scm_frame_end (); + return result; +} +#undef FUNC_NAME + +SCM_DEFINE (scm_bindtextdomain, "bindtextdomain", 1, 1, 0, + (SCM domainname, SCM directory), + "If optional parameter @var{directory} is supplied, " + "set message catalogs to directory @{directory}. " + "Return the directory bound to @var{domainname}.") +#define FUNC_NAME s_scm_bindtextdomain +{ + char *c_domain; + char *c_directory; + char const *c_result; + SCM result; + + scm_frame_begin (0); + + if (SCM_UNBNDP (directory)) + c_directory = NULL; + else + { + c_directory = scm_to_locale_string (directory); + scm_frame_free (c_directory); + } + + c_domain = scm_to_locale_string (domainname); + scm_frame_free (c_domain); + + c_result = bindtextdomain (c_domain, c_directory); + + if (c_result != NULL) + result = scm_from_locale_string (c_result); + else if (!SCM_UNBNDP (directory)) + SCM_SYSERROR; + else + result = SCM_BOOL_F; + + scm_frame_end (); + return result; +} +#undef FUNC_NAME + +SCM_DEFINE (scm_bind_textdomain_codeset, "bind-textdomain-codeset", 1, 1, 0, + (SCM domainname, SCM encoding), + "If optional parameter @var{encoding} is supplied, " + "set encoding for message catalogs of @{domainname}. " + "Return the encoding of @var{domainname}.") +#define FUNC_NAME s_scm_bind_textdomain_codeset +{ + char *c_domain; + char *c_encoding; + char const *c_result; + SCM result; + + scm_frame_begin (0); + + if (SCM_UNBNDP (encoding)) + c_encoding = NULL; + else + { + c_encoding = scm_to_locale_string (encoding); + scm_frame_free (c_encoding); + } + + c_domain = scm_to_locale_string (domainname); + scm_frame_free (c_domain); + + c_result = bind_textdomain_codeset (c_domain, c_encoding); + + if (c_result != NULL) + result = scm_from_locale_string (c_result); + else if (!SCM_UNBNDP (encoding)) + SCM_SYSERROR; + else + result = SCM_BOOL_F; + + scm_frame_end (); + return result; +} +#undef FUNC_NAME + +void +scm_init_i18n () +{ + scm_add_feature ("i18n"); +#include "libguile/i18n.x" +} + + +/* + Local Variables: + c-file-style: "gnu" + End: +*/ Index: libguile/i18n.h =================================================================== RCS file: libguile/i18n.h diff -N libguile/i18n.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ libguile/i18n.h 22 Sep 2004 00:39:28 -0000 @@ -0,0 +1,41 @@ +/* classes: h_files */ + +#ifndef SCM_I18N_H +#define SCM_I18N_H + +/* Copyright (C) 2004 Free Software Foundation, Inc. + * + * 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 "libguile/__scm.h" + +SCM_API SCM scm_gettext (SCM msgid, SCM domainname, SCM category); +SCM_API SCM scm_ngettext (SCM msgid, SCM msgid_plural, SCM n, SCM domainname, SCM category); +SCM_API SCM scm_textdomain (SCM domainname); +SCM_API SCM scm_bindtextdomain (SCM domainname, SCM directory); +SCM_API SCM scm_bind_textdomain_codeset (SCM domainname, SCM encoding); + +SCM_API int scm_i_to_lc_category (SCM category, int allow_lc_all); + +SCM_API void scm_init_i18n (void); + +#endif /* SCM_I18N_H */ + +/* + Local Variables: + c-file-style: "gnu" + End: +*/ Index: libguile/init.c =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/init.c,v retrieving revision 1.159 diff -u -r1.159 init.c --- libguile/init.c 24 Aug 2004 22:13:07 -0000 1.159 +++ libguile/init.c 22 Sep 2004 00:39:29 -0000 @@ -63,6 +63,7 @@ #include "libguile/hash.h" #include "libguile/hashtab.h" #include "libguile/hooks.h" +#include "libguile/i18n.h" #include "libguile/iselect.h" #include "libguile/ioext.h" #include "libguile/keywords.h" @@ -477,6 +478,7 @@ scm_init_properties (); scm_init_hooks (); /* Requires smob_prehistory */ scm_init_gc (); /* Requires hooks, async */ + scm_init_i18n (); scm_init_ioext (); scm_init_keywords (); scm_init_list (); Index: libguile/posix.c =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/posix.c,v retrieving revision 1.147 diff -u -r1.147 posix.c --- libguile/posix.c 7 Sep 2004 00:26:48 -0000 1.147 +++ libguile/posix.c 22 Sep 2004 00:39:34 -0000 @@ -39,6 +39,7 @@ #include "libguile/validate.h" #include "libguile/posix.h" +#include "libguile/i18n.h" \f #ifdef HAVE_STRING_H @@ -1365,7 +1366,7 @@ scm_frame_free (clocale); } - rv = setlocale (scm_to_int (category), clocale); + rv = setlocale (scm_i_to_lc_category (category, 1), clocale); if (rv == NULL) SCM_SYSERROR; @@ -1929,6 +1930,24 @@ #ifdef LC_ALL scm_c_define ("LC_ALL", scm_from_int (LC_ALL)); #endif +#ifdef LC_PAPER + scm_c_define ("LC_PAPER", scm_from_int (LC_PAPER)); +#endif +#ifdef LC_NAME + scm_c_define ("LC_NAME", scm_from_int (LC_NAME)); +#endif +#ifdef LC_ADDRESS + scm_c_define ("LC_ADDRESS", scm_from_int (LC_ADDRESS)); +#endif +#ifdef LC_TELEPHONE + scm_c_define ("LC_TELEPHONE", scm_from_int (LC_TELEPHONE)); +#endif +#ifdef LC_MEASUREMENT + scm_c_define ("LC_MEASUREMENT", scm_from_int (LC_MEASUREMENT)); +#endif +#ifdef LC_IDENTIFICATION + scm_c_define ("LC_IDENTIFICATION", scm_from_int (LC_IDENTIFICATION)); +#endif #ifdef PIPE_BUF scm_c_define ("PIPE_BUF", scm_from_long (PIPE_BUF)); #endif [-- Attachment #3: Type: text/plain, Size: 73 bytes --] -- GPG: D5D4E405 - 2F9B BCCC 8527 692A 04E3 331E FAF8 226A D5D4 E405 [-- Attachment #4: Type: text/plain, Size: 143 bytes --] _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: i18n, gettext support 2004-09-22 0:42 ` Marius Vollmer @ 2004-09-22 14:55 ` Bruno Haible 0 siblings, 0 replies; 28+ messages in thread From: Bruno Haible @ 2004-09-22 14:55 UTC (permalink / raw) Cc: guile-devel Marius Vollmer wrote: > Do you intend scm_to_lc_category to be part of the public API? No; its only uses are in the setlocale and gettext bindings. Bruno _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: i18n, gettext support 2004-09-02 16:06 ` Bruno Haible 2004-09-02 16:21 ` Bruno Haible @ 2004-09-02 17:32 ` Jan Nieuwenhuizen 1 sibling, 0 replies; 28+ messages in thread From: Jan Nieuwenhuizen @ 2004-09-02 17:32 UTC (permalink / raw) Cc: guile-devel Bruno Haible writes: > The autoconf test is still broken: AC_CHECK_LIB(intl, gettext) doesn't work. Hmm, that's strange, I just copied the socket/connect; probably should have tested it. > Also your patch uses SCM_STRING_CHARS, which is deprecated We used that in LilyPond, but it's just been deprecated so it seems. > Find here an extended patch. Thanks, please apply. Jan. -- Jan Nieuwenhuizen <janneke@gnu.org> | GNU LilyPond - The music typesetter http://www.xs4all.nl/~jantien | http://www.lilypond.org _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: i18n, gettext support 2004-09-01 16:25 ` Jan Nieuwenhuizen 2004-09-01 20:57 ` Bruno Haible @ 2004-09-01 21:44 ` Kevin Ryde 1 sibling, 0 replies; 28+ messages in thread From: Kevin Ryde @ 2004-09-01 21:44 UTC (permalink / raw) Cc: Bruno Haible, guile-devel Jan Nieuwenhuizen <janneke@gnu.org> writes: > > +SCM_API SCM scm_gettext (SCM string); dgettext is good too, and may as well have dcgettext at the same time. > +SCM_API SCM scm_bindtextdomain (SCM domainname, SCM directory); bind_textdomain_codeset will be good too until guile gets a strong grip on coding matters. (I would use it for instance to force utf8 for strings for gtk.) _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 28+ messages in thread
end of thread, other threads:[~2004-09-22 14:55 UTC | newest] Thread overview: 28+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2004-08-20 20:26 i18n, gettext support Bruno Haible 2004-08-23 0:58 ` Kevin Ryde 2004-09-01 16:25 ` Jan Nieuwenhuizen 2004-09-01 20:57 ` Bruno Haible 2004-09-02 9:38 ` Jan Nieuwenhuizen 2004-09-02 16:06 ` Bruno Haible 2004-09-02 16:21 ` Bruno Haible 2004-09-03 1:34 ` Kevin Ryde 2004-09-04 17:25 ` Bruno Haible 2004-09-07 0:13 ` Kevin Ryde 2004-09-07 12:38 ` Bruno Haible 2004-09-08 1:10 ` Kevin Ryde 2004-09-07 8:20 ` Jan Nieuwenhuizen 2004-09-07 14:16 ` Jan Nieuwenhuizen 2004-09-08 1:15 ` Kevin Ryde 2004-09-08 8:58 ` Jan Nieuwenhuizen 2004-09-08 10:39 ` Bruno Haible 2004-09-08 14:37 ` Jan Nieuwenhuizen 2004-09-08 16:37 ` Bruno Haible 2004-09-08 21:53 ` Jan Nieuwenhuizen 2004-09-08 22:45 ` Kevin Ryde 2004-09-08 23:46 ` Jan Nieuwenhuizen 2004-09-09 16:25 ` Jan Nieuwenhuizen 2004-09-15 11:20 ` Bruno Haible 2004-09-22 0:42 ` Marius Vollmer 2004-09-22 14:55 ` Bruno Haible 2004-09-02 17:32 ` Jan Nieuwenhuizen 2004-09-01 21:44 ` Kevin Ryde
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).