[Patches] Supporting libintl/gettext

Martin von Loewis loewis@informatik.hu-berlin.de
Mon, 29 May 2000 15:08:17 +0200 (MET DST)


This patch adds support for the gettext(3I) interface, as provided by
Solaris and GNU gettext (and therefore available on Linux and other
systems).

This is based on an earlier module named "intl". Because that name was
found confusing, I renamed the C module to "libintl", which is the
name of the header file providing these functions. The Python wrapper
module, which is the one that should be used in applications, is named
"gettext".

An open question is whether/if the interface should be supported on
systems that don't have gettext(3). GNU programs typically try to
support catgets(3) if gettext is not available, but I'd recommend
against such a strategy.

An alternative would be to support direct access to the message
catalog binary files. That is only possible if you know the file
format; fortunately, for GNU mo files (mo - machine object), it is
possible to write portable readers in Python. There are actually two
of them, one by Peter Funk, and one by James Henstridge. I haven't
approached either of them to ask whether they'd consider contributing
their code to Python.

The patch really is a one-liner, plus a shar file containing the real
code.

Regards,
Martin

Index: Setup.in
===================================================================
RCS file: /cvsroot/python/python/dist/src/Modules/Setup.in,v
retrieving revision 1.100
diff -u -r1.100 Setup.in
--- Setup.in	2000/05/26 19:02:42	1.100
+++ Setup.in	2000/05/28 09:42:44
@@ -141,6 +141,7 @@
                         # static Unicode character database
 
 #_locale _localemodule.c  # access to ISO C locale support
+#libintl libintlmodule.c  # message catalogs
 
 
 # Modules with some UNIX dependencies -- on by default:

#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.2).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `!/bin/sh' line above, then type `sh FILE'.
#
# Made on 2000-05-28 11:44 CEST by <martin@mira>.
# Source directory was `/usr/src/python'.
#
# Existing files will *not* be overwritten unless `-c' is specified.
#
# This shar contains:
# length mode       name
# ------ ---------- ------------------------------------------
#   3124 -rw-r--r-- Modules/libintlmodule.c
#   1651 -rw-r--r-- Lib/gettext.py
#
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=FAILED
locale_dir=FAILED
first_param="$1"
for dir in $PATH
do
  if test "$gettext_dir" = FAILED && test -f $dir/gettext \
     && ($dir/gettext --version >/dev/null 2>&1)
  then
    set `$dir/gettext --version 2>&1`
    if test "$3" = GNU
    then
      gettext_dir=$dir
    fi
  fi
  if test "$locale_dir" = FAILED && test -f $dir/shar \
     && ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
  then
    locale_dir=`$dir/shar --print-text-domain-dir`
  fi
done
IFS="$save_IFS"
if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED
then
  echo=echo
else
  TEXTDOMAINDIR=$locale_dir
  export TEXTDOMAINDIR
  TEXTDOMAIN=sharutils
  export TEXTDOMAIN
  echo="$gettext_dir/gettext -s"
fi
touch -am 1231235999 $$.touch >/dev/null 2>&1
if test ! -f 1231235999 && test -f $$.touch; then
  shar_touch=touch
else
  shar_touch=:
  echo
  $echo 'WARNING: not restoring timestamps.  Consider getting and'
  $echo "installing GNU \`touch', distributed in GNU File Utilities..."
  echo
fi
rm -f 1231235999 $$.touch
#
if mkdir _sh04578; then
  $echo 'x -' 'creating lock directory'
else
  $echo 'failed to create lock directory'
  exit 1
fi
# ============= Modules/libintlmodule.c ==============
if test ! -d 'Modules'; then
  $echo 'x -' 'creating directory' 'Modules'
  mkdir 'Modules'
fi
if test -f 'Modules/libintlmodule.c' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'Modules/libintlmodule.c' '(file already exists)'
else
  $echo 'x -' extracting 'Modules/libintlmodule.c' '(binary)'
  sed 's/^X//' << 'SHAR_EOF' | uudecode &&
begin 600 Modules/libintlmodule.c
M+RHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ
M*BHJ*BHJ*BHJ*BHJ*BHJ"D-O<'ER:6=H="`H0RD@,3DY-RP@,C`P,"!-87)T
M:6X@=F]N($SV=VES"@I097)M:7-S:6]N('1O('5S92P@8V]P>2P@;6]D:69Y
M+"!A;F0@9&ES=')I8G5T92!T:&ES('-O9G1W87)E(&%N9"!I=',*9&]C=6UE
M;G1A=&EO;B!F;W(@86YY('!U<G!O<V4@86YD('=I=&AO=70@9F5E(&ES(&AE
M<F5B>2!G<F%N=&5D+`IP<F]V:61E9"!T:&%T('1H92!A8F]V92!C;W!Y<FEG
M:'0@;F]T:6-E(&%P<&5A<B!I;B!A;&P@8V]P:65S+@H*5&AI<R!S;V9T=V%R
M92!C;VUE<R!W:71H(&YO('=A<G)A;G1Y+B!5<V4@870@>6]U<B!O=VX@<FES
M:RX**BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ
M*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ+PHC:6YC;'5D92`\<W1D:6\N:#X*
M(VEN8VQU9&4@/&5R<FYO+F@^"B-I;F-L=61E(#QL:6)I;G1L+F@^"B-I;F-L
M=61E(#QL;V-A;&4N:#X*(VEN8VQU9&4@(E!Y=&AO;BYH(@H*<W1A=&EC(&-H
M87(@9V5T=&5X=%]?9&]C7U];72`](`HB9V5T=&5X="AM<V=I9"D@+2!2971U
M<FX@=&AE('1R86YS;&%T960@;65S<V%G92XB"CL*"G-T871I8R!0>4]B:F5C
M="H*:6YT;%]?9V5T=&5X="A0>4]B:F5C="H@<V5L9BQ0>4]B:F5C="`J87)G
M<RD*>PH)8VAA<B`J:6X["@EI9B@A4'E!<F=?4&%R<V54=7!L92AA<F=S+")Z
M(BPF:6XI*0H)"7)E='5R;B`P.PH)<F5T=7)N(%!Y4W1R:6YG7T9R;VU3=')I
M;F<H9V5T=&5X="AI;BDI.PI]"@IS=&%T:6,@8VAA<B!D9V5T=&5X=%]?9&]C
M7U];72`](`HB9&=E='1E>'0H9&]M86EN+&US9VED*2`M(%)E='5R;B!T:&4@
M=')A;G-L871I;VX@;V8@=&AE(&UE<W-A9V4@=&AE('1E>'1U86P@9&]M86EN
M+B(*.PH*<W1A=&EC(%!Y3V)J96-T*@II;G1L7U]D9V5T=&5X="A0>4]B:F5C
M="H@<V5L9BQ0>4]B:F5C="`J87)G<RD*>PH)8VAA<B`J9&]M86EN+"II;CL*
M"6EF*"%0>4%R9U]087)S951U<&QE*&%R9W,L(GIZ(BPF9&]M86EN+"9I;BDI
M"@D)<F5T=7)N(#`["@ER971U<FX@4'E3=')I;F=?1G)O;5-T<FEN9RAD9V5T
M=&5X="AD;VUA:6XL:6XI*3L*?0H*<W1A=&EC(&-H87(@9&-G971T97AT7U]D
M;V-?7UM=(#T@"B)D8V=E='1E>'0H9&]M86EN+&US9VED+&-A=&5G;W)Y*2`M
M(%)E='5R;B!T:&4@=')A;G-L871I;VX@;V8@=&AE(&UE<W-A9V4N7&XB"B))
M;B!A9&1I=&EO;B!T;R!T:&4@:60@;V8@=&AE(&UE<W-A9V4L('1H:7,@9G5N
M8W1I;VX@97AP96-T<R!T:&4@=&5X='5A;%QN(@HB9&]M86EN(&%N9"!T:&4@
M;&]C86QE(&-A=&5G;W)Y+B(*.PH*<W1A=&EC(%!Y3V)J96-T*@II;G1L7U]D
M8V=E='1E>'0H4'E/8FIE8W0@*G-E;&8L4'E/8FIE8W0@*F%R9W,I"GL*"6-H
M87(@*F1O;6%I;BPJ;7-G:60["@EI;G0@8V%T96=O<GD["@EI9B@A4'E!<F=?
M4&%R<V54=7!L92AA<F=S+")Z>FDB+"9D;VUA:6XL)FUS9VED+"9C871E9V]R
M>2DI"@D)<F5T=7)N(#`["@ER971U<FX@4'E3=')I;F=?1G)O;5-T<FEN9RAD
M8V=E='1E>'0H9&]M86EN+&US9VED+&-A=&5G;W)Y*2D["GT*"G-T871I8R!C
M:&%R('1E>'1D;VUA:6Y?7V1O8U]?6UT@/2`*(G1E>'1D;VUA:6XH6VYE=V1O
M;6%I;ETI("T@<W)I;F<N7&XB"B)3970@=&AE('1E>'1D;VUA:6X@=&\@;F5W
M9&]M86EN(&EF(&=I=F5N.R!R971U<FX@=&AE(&YE=R!D;VUA:6XN(@H["@IS
M=&%T:6,@4'E/8FIE8W0J"FEN=&Q?7W1E>'1D;VUA:6XH4'E/8FIE8W0J('-E
M;&8L4'E/8FIE8W0J(&%R9W,I"GL*"6-H87(@*F1O;6%I;B`](#`["@EC:&%R
M("IR97-U;'0["@EI9B@A4'E!<F=?4&%R<V54=7!L92AA<F=S+")\>B(L)F1O
M;6%I;BDI<F5T=7)N(#`["@ER97-U;'0@/2`@=&5X=&1O;6%I;BAD;VUA:6XI
M.PH):68H<F5S=6QT*0H)"7)E='5R;B!0>5-T<FEN9U]&<F]M4W1R:6YG*')E
M<W5L="D["@EE;'-E"@D)<F5T=7)N(%!Y17)R7U-E=$9R;VU%<G)N;RA0>45X
M8U]/4T5R<F]R*3L*?0H*<W1A=&EC(&-H87(@8FEN9'1E>'1D;VUA:6Y?7V1O
M8U]?6UT@/2`*(F)I;F1T97AT9&]M86EN*&1O;6%I;ELL9&ER;F%M95TI("T@
M<W)I;F<N7&XB"B)":6YD('1H92!T97AT=6%L(&1O;6%I;B!T;R!T:&4@9&ER
M96-T;W)Y(&1I<FYA;64[(')E='5R;B!T:&4@<V5L96-T960@7&XB"B)D:7)E
M8W1O<GDN($EF(&1I<FYA;64@:7,@;VUI='1E9"P@<F5T=7)N(&]L9"!S971T
M:6YG+B(*.PH*<W1A=&EC(%!Y3V)J96-T*@II;G1L7U]B:6YD=&5X=&1O;6%I
M;BA0>4]B:F5C="H@<V5L9BQ0>4]B:F5C="IA<F=S*0I["@EC:&%R("ID;VUA
M:6XL("ID:7)N86UE(#T@,#L*"6-H87(@*G)E<W5L=#L*"6EF*"%0>4%R9U]0
M87)S951U<&QE*&%R9W,L(GI\>B(L)F1O;6%I;BPF9&ER;F%M92DI"@D)<F5T
M=7)N(#`["@ER97-U;'0@/2!B:6YD=&5X=&1O;6%I;BAD;VUA:6XL9&ER;F%M
M92D["@EI9BAR97-U;'0I"@D)<F5T=7)N(%!Y4W1R:6YG7T9R;VU3=')I;F<H
M<F5S=6QT*3L*"65L<V4*"0ER971U<FX@4'E%<G)?4V5T1G)O;45R<FYO*%!Y
M17AC7T]317)R;W(I.PI]"@IS=&%T:6,@<W1R=6-T(%!Y365T:&]D1&5F(&EN
M=&Q?7TUE=&AO9'-;72`]('L*("![(F=E='1E>'0B+"`@("`@("!I;G1L7U]G
M971T97AT+"`@("`@("!-151(7U9!4D%21U,L9V5T=&5X=%]?9&]C7U]]+`H@
M('LB9&=E='1E>'0B+"`@("`@(&EN=&Q?7V1G971T97AT+"`@("`@($U%5$A?
M5D%205)'4RQD9V5T=&5X=%]?9&]C7U]]+`H@('LB9&-G971T97AT(BP@("`@
M(&EN=&Q?7V1C9V5T=&5X="P@("`@($U%5$A?5D%205)'4RQD8V=E='1E>'1?
M7V1O8U]??2P*("![(G1E>'1D;VUA:6XB+"`@("!I;G1L7U]T97AT9&]M86EN
M+"`@("!-151(7U9!4D%21U,L=&5X=&1O;6%I;E]?9&]C7U]]+`H@('LB8FEN
M9'1E>'1D;VUA:6XB+&EN=&Q?7V)I;F1T97AT9&]M86EN+$U%5$A?5D%205)'
M4RQB:6YD=&5X=&1O;6%I;E]?9&]C7U]]+`H@('M.54Q,+"!.54Q,?0I].PH*
M=F]I9`II;FET;&EB:6YT;"@I"GL*"5!Y3V)J96-T("IM+"ID.PH);3U0>5])
M;FET36]D=6QE*")L:6)I;G1L(BQI;G1L7U]-971H;V1S*3L*"6EF*%!Y17)R
M7T]C8W5R<F5D*"DI"@D)4'E?1F%T86Q%<G)O<B@B0V%N)W0@:6YI=&EA;&EZ
392!M;V1U;&4@:6YT;"(I.PI]"F%T
`
end
SHAR_EOF
  $shar_touch -am 05281140100 'Modules/libintlmodule.c' &&
  chmod 0644 'Modules/libintlmodule.c' ||
  $echo 'restore of' 'Modules/libintlmodule.c' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'Modules/libintlmodule.c:' 'MD5 check failed'
93148d6ba23102627fa5571438b28261  Modules/libintlmodule.c
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'Modules/libintlmodule.c'`"
    test 3124 -eq "$shar_count" ||
    $echo 'Modules/libintlmodule.c:' 'original size' '3124,' 'current size' "$shar_count!"
  fi
fi
# ============= Lib/gettext.py ==============
if test ! -d 'Lib'; then
  $echo 'x -' 'creating directory' 'Lib'
  mkdir 'Lib'
fi
if test -f 'Lib/gettext.py' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'Lib/gettext.py' '(file already exists)'
else
  $echo 'x -' extracting 'Lib/gettext.py' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'Lib/gettext.py' &&
"Functions for accessing message catalogs."
X
try:
X    from libintl import *
except ImportError:
X    import sys,os
X    _join = os.path.join
X    _default_domain = None
X    _directories = {}
X    _default_directory
X    # XXX: set from locale module
X    _lang = "C"
X    from locale import LC_CTYPE, LC_TIME, LC_COLLATE
X    from locale import LC_MONETARY, LC_MESSAGES, LC_NUMERIC
X    _categories = {
X        LC_CTYPE : 'LC_CTYPE',
X        LC_TIME : 'LC_TIME',
X        LC_COLLATE : 'LC_COLLATE',
X        LC_MONETARY : 'LC_MONETARY',
X        LC_MESSAGES : 'LC_MESSAGES',
X        LC_NUMERIC : 'LC_NUMERIC'
X        }
X
X    def textdomain(d):
X        global _default_domain
X        _default_domain = d
X        return d
X
X    def bindtextdomain(domain,dir=None):
X        if dir is None:
X            return _directories.get(domain,_join(sys.prefix,"share","locale"))
X        _directories[domain] = dir
X
X    # This is the critical function in the emulation package.
X    # Possible candidate implementations are
X    # James Henstridge's <james@daa.com.au> gettext.py from GNOME
X    # http://cvs.gnome.org/lxr/source/gnome-python/pygnome/gettext.py
X    # Peter Funk's fintl.py
X    # http://sourceforge.net/snippet/detail.php?type=snippet&id=100059
X    
X    def dcgettext(domain,msgid,category):
X        dir = _join(bindtextdomain(domain),_lang,_categories[category])
X        file = _join(dir, domain, ".mo")
X        # XXX need actual file reader
X        raise NotImplementedError("mo file reader")
X
X    def dgettext(domain,msgid):
X        return dcgettext(domain,msgid,LC_MESSAGES)
X
X    def gettext(msgid):
X        return dcgettext(_default_domain, msgid, LC_MESSAGES)
SHAR_EOF
  $shar_touch -am 05281129100 'Lib/gettext.py' &&
  chmod 0644 'Lib/gettext.py' ||
  $echo 'restore of' 'Lib/gettext.py' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'Lib/gettext.py:' 'MD5 check failed'
14a9bfef353ef32c99d1f0959d950755  Lib/gettext.py
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'Lib/gettext.py'`"
    test 1651 -eq "$shar_count" ||
    $echo 'Lib/gettext.py:' 'original size' '1651,' 'current size' "$shar_count!"
  fi
fi
rm -fr _sh04578
exit 0