Locale-gettext-1.07/0000755000076600007660000000000012602267500013726 5ustar vandryvandryLocale-gettext-1.07/t/0000755000076600007660000000000012602267500014171 5ustar vandryvandryLocale-gettext-1.07/t/bind.t0000644000076600007660000000045010177252744015302 0ustar vandryvandry#!/usr/bin/env perl -w use strict; use Test; BEGIN { plan tests => 1 } use Locale::gettext; bindtextdomain("foo", "dirname"); if ((bindtextdomain("foo") eq 'dirname') && (bindtextdomain("foo") eq 'dirname')) { ok(1); } else { print "[", bindtextdomain("foo"), "]\n"; ok(0); } exit; __END__ Locale-gettext-1.07/t/raw.t0000644000076600007660000000046410247214010015142 0ustar vandryvandry#!/usr/bin/env perl -w use strict; use Test; BEGIN { plan tests => 1 } require "test_data/gen_test_data.pl"; gen("foo"); use Locale::gettext; my $d = Locale::gettext->domain_raw("foo"); $d->dir("test_data"); if ($d->get("No worries") eq "Sans craintes") { ok(1); } else { ok(0); } undef $d; exit; __END__ Locale-gettext-1.07/t/use.t0000644000076600007660000000016210177244561015160 0ustar vandryvandry#!/usr/bin/env perl -w use strict; use Test; BEGIN { plan tests => 1 } use Locale::gettext; ok(1); exit; __END__ Locale-gettext-1.07/t/frconvert.t0000644000076600007660000000072212602263341016366 0ustar vandryvandry#!/usr/bin/env perl -w use strict; use Test; BEGIN { plan tests => 1 } require "test_data/gen_test_data.pl"; gen("foo"); use Locale::gettext; my $d; eval { $d = Locale::gettext->domain("foo"); }; if ($@ =~ /Encode module not available/) { skip("Locale::gettext->domain not available, skipping", 0) } elsif ($@ ne '') { die $@; } else { $d->dir("test_data"); if ($d->get("No problem") eq "Pas de probl\x{e8}me") { ok(1); } else { ok(0); } } exit; __END__ Locale-gettext-1.07/t/jaconvert.t0000644000076600007660000000076310177264662016372 0ustar vandryvandry#!/usr/bin/env perl -w use strict; use Test; BEGIN { plan tests => 1 } require "test_data/gen_test_data.pl"; gen("jaeuc"); use Locale::gettext; my $d; eval { $d = Locale::gettext->domain("jaeuc"); }; if ($@ =~ /Encode module not available/) { skip("Locale::gettext->domain not available, skipping", 0) } elsif ($@ ne '') { die $@; } else { $d->dir("test_data"); if ($d->get("test") eq "\x{30c6}\x{30b9}\x{30c8}") { ok(1); } else { print $d->get("test"), "\n"; ok(0); } } exit; __END__ Locale-gettext-1.07/Makefile.PL0000644000076600007660000000356612577042177015726 0ustar vandryvandryuse ExtUtils::MakeMaker; use Config; my $cc; if (defined($ENV{'CC'})) { $cc = $ENV{'CC'}; } else { $cc = $Config{'cc'}; } my $libs = ''; unless (conftest("char *x = gettext(\"foo\");", "gettext", 0)) { # try with -lintl $libs = "-lintl"; unless (conftest("char *x = gettext(\"foo\");", "gettext", 0)) { unlink("conftest.c"); unlink("conftest"); die "gettext function not found. Please install libintl"; } } open(CONFIG, ">config.h"); print CONFIG "/* Generated automatically by ", $0, ". Do not edit */\n"; conftest("char *x = dcgettext(\"foo\", \"bar\", 0);", "dgettext", 1); conftest("char *x = ngettext(\"foo\", \"foos\", 1);", "ngettext", 1); conftest("char *x = bind_textdomain_codeset(\"foo\", \"UTF-8\");", "bind_textdomain_codeset", 1); close CONFIG; unlink("conftest.c"); unlink("conftest"); WriteMakefile( NAME => "Locale::gettext", LIBS => ($libs eq '') ? [] : [$libs], VERSION_FROM => 'gettext.pm', META_MERGE => { resources => { repository => 'https://github.com/vandry/Perl-Locale-gettext', license => 'http://dev.perl.org/licenses/', }, }, ABSTRACT => "Perl bindings for POSIX i18n gettext functions", AUTHOR => "Kim Vandry ", LICENSE => 'perl', ); sub conftest { my ($testcode, $func, $record) = @_; print "checking for ", $func; print(" in ", $libs) if ($libs ne ''); print "..."; open(TEST, ">conftest.c"); print TEST "#include \n\nint main(int argc, char **argv)\n{\n"; print TEST $testcode; print TEST "return 0;}\n"; close TEST; open(SAVE, ">&STDERR"); open(STDERR, ">/dev/null"); system($cc . " -o conftest " . " conftest.c " . $libs); my $exitstatus = $?; open(STDERR, ">&SAVE"); if ($exitstatus != 0) { print " no\n"; return 0; } else { print " yes\n"; if ($record) { print CONFIG "#define HAVE_", uc($func), "\n"; } return 1; } } Locale-gettext-1.07/test_data/0000755000076600007660000000000012602267500015676 5ustar vandryvandryLocale-gettext-1.07/test_data/gen_test_data.pl0000644000076600007660000000310112602266753021040 0ustar vandryvandryuse strict; sub gen { my ($domain) = @_; my $messages; my $language; unless (open(LOCALE, "locale|")) { doskip(); } while () { if (/^LC_MESSAGES=\"(.*)\"$/) { $messages = $1; } elsif (/^LC_MESSAGES=(.*)$/) { $messages = $1; } elsif (/^LANGUAGE=\"(.*)\"$/) { $language = $1; } elsif (/^LANGUAGE=(.*)$/) { $language = $1; } } close LOCALE; if ($? != 0) { doskip(); } if (!defined($messages)) { skip("cannot run test without a locale set", 0); exit 0; } if ($messages eq 'C') { skip("cannot run test in the C locale", 0); exit 0; } if ($messages eq 'POSIX') { skip("cannot run test in the POSIX locale", 0); exit 0; } if (defined($language) && $language) { # In GNU gettext, $LANGUAGE overrides # all the other environment variables, # for message translations only. # https://www.gnu.org/software/gettext/manual/html_node/The-LANGUAGE-variable.html#The-LANGUAGE-variable # The library will look first for the first entry in # that list, so give it what it wants. $messages = (split(':', $language))[0]; } mkdir "test_data/" . $messages, 0755 unless (-d "test_data/" . $messages); mkdir "test_data/" . $messages . "/LC_MESSAGES", 0755 unless (-d "test_data/" . $messages . "/LC_MESSAGES"); unless (-r ("test_data/" . $messages . "/LC_MESSAGES/" . $domain . ".mo")) { system "msgfmt", "-o", "test_data/" . $messages . "/LC_MESSAGES/" . $domain . ".mo", "test_data/" . $domain . ".po"; if ($? != 0) { doskip(); } } } sub doskip { skip("could not generate test data, skipping test", 0); exit 0; } 1; Locale-gettext-1.07/test_data/jaeuc.po0000644000076600007660000000013110177256746017337 0ustar vandryvandrymsgid "" msgstr "Content-Type: text/plain; charset=euc-jp" msgid "test" msgstr "¥Æ¥¹¥È" Locale-gettext-1.07/test_data/foo.po0000644000076600007660000000023010177266574017033 0ustar vandryvandrymsgid "" msgstr "Content-Type: text/plain; charset=iso-8859-15" msgid "No worries" msgstr "Sans craintes" msgid "No problem" msgstr "Pas de problème" Locale-gettext-1.07/gettext.xs0000644000076600007660000000457710247213714016004 0ustar vandryvandry#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include #include #include "config.h" static double constant(char *name, int arg) { errno = 0; if (strEQ(name, "LC_CTYPE")) return LC_CTYPE; if (strEQ(name, "LC_NUMERIC")) return LC_NUMERIC; if (strEQ(name, "LC_COLLATE")) return LC_COLLATE; if (strEQ(name, "LC_MONETARY")) return LC_MONETARY; if (strEQ(name, "LC_MESSAGES")) return LC_MESSAGES; if (strEQ(name, "LC_ALL")) return LC_ALL; errno = EINVAL; return 0; } #define ANY_MISSING 0 #ifndef HAVE_DGETTEXT /* if dgettext is not there, neither will dcgettext, dngettext and dcngettext be. But only deal with dngettext and dcngettext if they will not be dealt with later because of ngettext */ #define dgettext(a,b) not_here("dgettext") #define dcgettext(a,b,c) not_here("dcgettext") #ifdef HAVE_NGETTEXT #define dngettext(a,b,c,d) not_here("dngettext") #define dcngettext(a,b,c,d,e) not_here("dcngettext") #endif #undef ANY_MISSING #define ANY_MISSING 1 #endif #ifndef HAVE_NGETTEXT #define ngettext(a,b,c) not_here("ngettext") #define dngettext(a,b,c,d) not_here("dngettext") #define dncgettext(a,b,c,d,e) not_here("dcngettext") #undef ANY_MISSING #define ANY_MISSING 1 #endif #ifndef HAVE_BIND_TEXTDOMAIN_CODESET #define bind_textdomain_codeset(a,b) not_here("bind_textdomain_codeset") #undef ANY_MISSING #define ANY_MISSING 1 #endif #if ANY_MISSING static int not_here(char *s) { croak("Locale::gettext::%s not implemented on this architecture", s); return -1; } #endif MODULE = Locale::gettext PACKAGE = Locale::gettext double constant(name,arg) char * name int arg char * gettext(msgid) char * msgid char * dcgettext(domainname, msgid, category) char * domainname char * msgid int category char * dgettext(domainname, msgid) char * domainname char * msgid char * ngettext(msgid, msgid_plural, n) char * msgid char * msgid_plural unsigned long n char * dcngettext(domainname, msgid, msgid_plural, n, category) char * domainname char * msgid char * msgid_plural unsigned long n int category char * dngettext(domainname, msgid, msgid_plural, n) char * domainname char * msgid char * msgid_plural unsigned long n char * textdomain(domain) char * domain char * bindtextdomain(domain, dirname = NULL) char * domain char * dirname char * bind_textdomain_codeset(domain, codeset = NULL) char * domain char * codeset Locale-gettext-1.07/README0000644000076600007660000001475312602267167014631 0ustar vandryvandryLocale::gettext version 1.07 This is a perl5 module quickly written to gain access to the C library functions for internatialization. They work just like the C versions. As of version 1.04, an object oriented interface more suitable to native Perl programs is available. Locale::gettext is Copyright 1996..2005 by Kim Vandry . All rights reserved. This library is free software; you may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file. Changes ------- 1.07 Fix test failures caused by $LANGUAGE being set 1.06 Bugfix: #104667 Makefile.PL libaries need to be listed after .o files Bugfix: #104668 ensure availability of locale API, correct typo in documentation Add META.yml (Fixes #91921) 1.05 Bugfix: [cpan #13042] useless #ifdef should be #if Bugfix: [cpan #13044] make test fails when using POSIX locale 1.04 Add several functions provided by the GNU gettext library Create object oriented interface 1.03 Fix error in README file 1.02 Include a License 1.01 Changed from "gettext" to "Locale::gettext" (i.e. moved under Locale::) on the advice of several people Small "lint" fix from schwern@starmedia.net 1.00 Initial version TODO ---- A TIEHASH interface Here's a quick tutorial. ----------------------- Note that your vendor's implementation of these functions may be a bit different, but I think that in general these are quite standard POSIX functions. Kim Vandry Mlink Internet July 1996 INTERNATIONALIZING YOUR PROGRAM Step 1 ------ If you've already written your code, you need to wrap the gettext() function around all of the text strings. Needless to say, this is much easier if you do it while you write. # create object for oo interface my $d = Locale::gettext->domain("my_program"); print "Welcome to my program\n"; # oo print $d->get("Welcome to my program"), "\n"; # traditional print gettext("Welcome to my program"), "\n"; Note that you probably don't want to include that newline in the gettext() call, nor any formatting codes such as HTML tags. The argument to gettext() is the text string in the default language or locale. This is known as the C locale and should probably be usually English. Step 2 ------ Do the apropriate initializations at the beginning of your program: # use POSIX; # for setlocale() use Locale::gettext; # # The following statement initializes the locale handling # code in the C library. Normally, it causes it to read # in the environment variables that determine the current # locale. # # The first parameter is the category you would # like to initialize locale information for. You can use # LC_ALL for this, which will set locale information for # all categories, including LC_CTYPE, LC_TIME, LC_NUMERIC, # etc.. # # I recommend that you set only LC_MESSAGES (text strings) # or LC_CTYPE (character sets) and LC_TIME (time # conventions) too at most. You may find that if you set # LC_NUMERIC or some other categories, you will start # outputting decimal numbers with strange thousand separators # and decimal points and they will be unparseable in # other countries. # # The second parameter is the locale name. If it is an # empty string, then this information will be fetched from # environment variables. # # Note that setlocale() will cause every part of your # program to start operating in the new, non default (C) # locale, including C library functions. So don't be # surprised if POSIX::ctime returns "Montag, 22. Juli 1996, # 12:08:25 Uhr EDT" instead of "Mon Jul 22 12:08:25 EDT 1996" # If you set LC_TIME or LC_ALL using setlocale(). # setlocale(LC_MESSAGES, ""); # # Decide on a unique identifier that will distinguish your # program's text strings in the LC_MESSAGES database. This # would usually be the name of your program # # By default, locale information is found in OS dependant # system directories such as /usr/lib/locale, or any directory # found in the $PATH-like environment variable $NLSPATH. # I recommend that you do _not_ install files in /usr. If # your program is installed in a directory tree such as # /opt/my_package_name/{bin,man,lib,etc}, then you could # use /opt/my_package_name/locale to store locale information # specific to your program, or you could put in somewhere # in /usr/local/lib. # # Wherever you put it, if it is not one of the default # directories, you will need to call bindtextdomain() to # tell the library where to find your files. The first # parameter is your database's identifier that you chose # above. # # oo interface: my $d = Locale::gettext->domain("my_domain"); $d->dir("/opt/my_package_name/locale"); # traditional interface: bindtextdomain("my_domain", "/opt/my_package_name/locale"); textdomain("my_domain"); # That's it for the initializations Step 3 ------ Test to see if your program still works after all these mods :-) Step 4 ------ TRANSLATE! Read msgfmt(1) for details on this. Basically, for each locale other than the default, you need to create a file like this: (Note: I do not speak German, I'm making an attempt here :-) Call this file with the .po extension. --BEGIN domain "my_domain" msgid "Welcome to my program" msgstr "Willkommen in mein Program" msgid "Help" msgstr "Hilfe" --END The "msgid" parameter must match exactly the argument to the gettext() function, and "msgstr" is the corresponding translation. You can use the xgettext(1) utility to initially construct this file from all of the gettext() calls in your source code. It was designed for C but it works OK with perl. Step 5 ------ Compile the .po file $ msgfmt my_file.po This will create a file called my_domain.mo (default messages.mo) which you should place in the /LC_MESSAGES/my_domain.mo subdirectory of either a system default directory, a directory in $NLSPATH, or the directory argument to bindtextdomain(). Replace with the name of the locale for which this file is created. For example: $ mkdir -p /opt/my_package/locale/de/LC_MESSAGES $ mkdir -p /opt/my_package/locale/fr/LC_MESSAGES $ cd /path/to/my/source/code $ cd de $ msgfmt my_domain.po $ mv my_domain.mo /opt/my_package/locale/de/LC_MESSAGES $ cd ../fr $ msgfmt my_domain.po $ mv my_domain.mo /opt/my_package/locale/fr/LC_MESSAGES Step 6 ------ Test it out $ my_program Welcome to my program $ LANG=fr my_program Bienvenue à mon programme $ LANG=de my_program Willkommen in mein Program (Or, set only the messages category instead of the whole locale) $ LC_MESSAGES=fr $ export LC_MESSAGES $ my_program Bienvenue à mon programme Locale-gettext-1.07/MANIFEST0000644000076600007660000000051612602267500015061 0ustar vandryvandrygettext.pm gettext.xs Makefile.PL README t/bind.t t/frconvert.t t/jaconvert.t t/raw.t t/use.t test_data/foo.po test_data/gen_test_data.pl test_data/jaeuc.po MANIFEST META.yml Module YAML meta-data (added by MakeMaker) META.json Module JSON meta-data (added by MakeMaker) Locale-gettext-1.07/gettext.pm0000644000076600007660000001530612602267223015757 0ustar vandryvandrypackage Locale::gettext; =head1 NAME Locale::gettext - message handling functions =head1 SYNOPSIS use Locale::gettext; use POSIX; # Needed for setlocale() setlocale(LC_MESSAGES, ""); # OO interface my $d = Locale::gettext->domain("my_program"); print $d->get("Welcome to my program"), "\n"; # (printed in the local language) # Direct access to C functions textdomain("my_program"); print gettext("Welcome to my program"), "\n"; # (printed in the local language) =head1 DESCRIPTION The gettext module permits access from perl to the gettext() family of functions for retrieving message strings from databases constructed to internationalize software. =cut use Carp; use POSIX qw(:locale_h); require Exporter; require DynaLoader; @ISA = qw(Exporter DynaLoader); BEGIN { eval { require Encode; $encode_available = 1; }; import Encode if ($encode_available); } $VERSION = "1.07" ; %EXPORT_TAGS = ( locale_h => [qw(LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES LC_ALL)], libintl_h => [qw(gettext textdomain bindtextdomain dcgettext dgettext ngettext dngettext dcngettext bind_textdomain_codeset)], ); Exporter::export_tags(); @EXPORT_OK = qw( ); bootstrap Locale::gettext $VERSION; sub AUTOLOAD { local $! = 0; my $constname = $AUTOLOAD; $constname =~ s/.*:://; my $val = constant($constname, (@_ ? $_[0] : 0)); if ($! == 0) { *$AUTOLOAD = sub { $val }; } else { croak "Missing constant $constname"; } goto &$AUTOLOAD; } =over 2 =item $d = Locale::gettext->domain(DOMAIN) =item $d = Locale::gettext->domain_raw(DOMAIN) Creates a new object for retrieving strings in the domain B and returns it. C requests that strings be returned as Perl strings (possibly with wide characters) if possible while C requests that octet strings directly from functions like C. =cut sub domain_raw { my ($class, $domain) = @_; my $self = { domain => $domain, raw => 1 }; bless $self, $class; } sub domain { my ($class, $domain) = @_; unless ($encode_available) { croak "Encode module not available, cannot use Locale::gettext->domain"; } my $self = { domain => $domain, raw => 0 }; bless $self, $class; eval { bind_textdomain_codeset($self->{domain}, "UTF-8"); }; if ($@ =~ /not implemented/) { # emulate it $self->{emulate} = 1; } elsif ($@ ne '') { die; # some other problem } $self; } =item $d->get(MSGID) Calls C to return the translated string for the given B. =cut sub get { my ($self, $msgid) = @_; $self->_convert(dgettext($self->{domain}, $msgid)); } =item $d->cget(MSGID, CATEGORY) Calls C to return the translated string for the given B in the given B. =cut sub cget { my ($self, $msgid, $category) = @_; $self->_convert(dcgettext($self->{domain}, $msgid, $category)); } =item $d->nget(MSGID, MSGID_PLURAL, N) Calls C to return the translated string for the given B or B depending on B. =cut sub nget { my ($self, $msgid, $msgid_plural, $n) = @_; $self->_convert(dngettext($self->{domain}, $msgid, $msgid_plural, $n)); } =item $d->ncget(MSGID, MSGID_PLURAL, N, CATEGORY) Calls C to return the translated string for the given B or B depending on B in the given B. =cut sub ncget { my ($self, $msgid, $msgid_plural, $n, $category) = @_; $self->_convert(dcngettext($self->{domain}, $msgid, $msgid_plural, $n, $category)); } =item $d->dir([NEWDIR]) If B is given, calls C to set the name of the directory where messages for the domain represented by C<$d> are found. Returns the (possibly changed) current directory name. =cut sub dir { my ($self, $newdir) = @_; if (defined($newdir)) { bindtextdomain($self->{domain}, $newdir); } else { bindtextdomain($self->{domain}); } } =item $d->codeset([NEWCODE]) For instances created with Cdomain_raw>, manuiplates the character set of the returned strings. If B is given, calls C to set the character encoding in which messages for the domain represented by C<$d> are returned. Returns the (possibly changed) current encoding name. =cut sub codeset { my ($self, $codeset) = @_; if ($self->{raw} < 1) { warn "Locale::gettext->codeset: meaningful only for instances created with domain_raw"; return; } if (defined($codeset)) { bind_textdomain_codeset($self->{domain}, $codeset); } else { bind_textdomain_codeset($self->{domain}); } } sub _convert { my ($self, $str) = @_; return $str if ($self->{raw}); # thanks to the use of UTF-8 in bind_textdomain_codeset, the # result should always be valid UTF-8 when raw mode is not used. if ($self->{emulate}) { delete $self->{emulate}; $self->{raw} = 1; my $null = $self->get(""); if ($null =~ /charset=(\S+)/) { $self->{decode_from} = $1; $self->{raw} = 0; } #else matches the behaviour of glibc - no null entry # means no conversion is done } if ($self->{decode_from}) { return decode($self->{decode_from}, $str); } else { return decode_utf8($str); } } sub DESTROY { my ($self) = @_; } =back gettext(), dgettext(), and dcgettext() attempt to retrieve a string matching their C parameter within the context of the current locale. dcgettext() takes the message's category and the text domain as parameters while dgettext() defaults to the LC_MESSAGES category and gettext() defaults to LC_MESSAGES and uses the current text domain. If the string is not found in the database, then C is returned. ngettext(), dngettext(), and dcngettext() function similarily but implement differentiation of messages between singular and plural. See the documentation for the corresponding C functions for details. textdomain() sets the current text domain and returns the previously active domain. I instructs the retrieval functions to look for the databases belonging to domain C in the directory C I instructs the retrieval functions to translate the returned messages to the character encoding given by B if the encoding of the message catalog is known. =head1 NOTES Not all platforms provide all of the functions. Functions that are not available in the underlying C library will not be available in Perl either. Perl programs should use the object interface. In addition to being able to return native Perl wide character strings, C will be emulated if the C library does not provide it. =head1 VERSION 1.07. =head1 SEE ALSO gettext(3i), gettext(1), msgfmt(1) =head1 AUTHOR Kim Vandry =cut 1; Locale-gettext-1.07/META.yml0000664000076600007660000000112612602267500015201 0ustar vandryvandry--- abstract: 'Perl bindings for POSIX i18n gettext functions' author: - 'Kim Vandry ' build_requires: ExtUtils::MakeMaker: 0 configure_requires: ExtUtils::MakeMaker: 0 dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 6.66, CPAN::Meta::Converter version 2.120921' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 name: Locale-gettext no_index: directory: - t - inc requires: {} resources: license: http://dev.perl.org/licenses/ repository: https://github.com/vandry/Perl-Locale-gettext version: 1.07 Locale-gettext-1.07/META.json0000664000076600007660000000201512602267500015347 0ustar vandryvandry{ "abstract" : "Perl bindings for POSIX i18n gettext functions", "author" : [ "Kim Vandry " ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 6.66, CPAN::Meta::Converter version 2.120921", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "Locale-gettext", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "runtime" : { "requires" : {} } }, "release_status" : "stable", "resources" : { "license" : [ "http://dev.perl.org/licenses/" ], "repository" : { "url" : "https://github.com/vandry/Perl-Locale-gettext" } }, "version" : "1.07" }