Subject: | [PATCH] configurability enhancements |
Attached is a patch that implements a 100% backward-compatible overhaul
of I18N.pm to allow much greater configurability. This patch allows the
developer to override any Locale::Maketext::Simple parameter, if needed.
I found this necessary to get the encoding to work right with
Template-Toolkit for my auto-generated Locale::Maketext lexicons (i.e.
passing 'Decode => 0').
This patch also adds the additional feature of reporting the languages
of all the lexicons that are installed. This facilitates, say, writing
pulldowns for language selection in HTML.
I know you folks prefer that patches like this be proposed on the
mailing list instead of in RT, but it's just too time consuming to
follow the Catalyst lists...
Subject: | i18n.patch |
--- /Users/chris/Work/catalyst/Catalyst-Plugin-I18N/I18N.pm 2006-12-06 13:53:17.000000000 -0600
+++ inc/Catalyst/Plugin/I18N/Configurable.pm 2007-02-20 09:25:38.000000000 -0600
@@ -1,21 +1,24 @@
-package Catalyst::Plugin::I18N;
+package Catalyst::Plugin::I18N::Configurable;
+use warnings;
use strict;
use NEXT;
use I18N::LangTags ();
use I18N::LangTags::Detect;
+use File::Spec;
+# Don't "use" because we want to delay import()
require Locale::Maketext::Simple;
-our $VERSION = '0.05';
+our $VERSION = '0.01';
=head1 NAME
-Catalyst::Plugin::I18N - I18N for Catalyst
+Catalyst::Plugin::I18N::Configurable - I18N for Catalyst
=head1 SYNOPSIS
- use Catalyst 'I18N';
+ use Catalyst 'I18N::Configurable';
print join ' ', @{ $c->languages };
$c->languages( ['de'] );
@@ -50,27 +53,111 @@
=head3 setup
+Figure out where the I18N C<.po> or C<.pm> files are located (by
+default: F<lib/MyApp/I18N/>) Initialize Locale::Maketext::Simple.
+Collect a list of which languages have I18N files present.
+
+Configuration options -- all of these can be set like this example:
+
+ MyApp->config(i18n => {
+ dir => '/usr/share/MyApp/localization',
+ locale_maketext_simple_opts => {
+ Style => 'gettext',
+ Decode => 0,
+ },
+ });
+
+=over
+
+=item pkg => $class
+
+The parent class of your I18N namespace. Defaults to the package of
+your Catalyst app (e.g. C<MyApp>).
+
+=item subpkg => $subdir
+
+The directory under your app which contains the localization files.
+Defaults to C<I18N>.
+
+=item dir => $dir
+
+The path to a directory which contains the localization files. If
+this is set, the C<subpkg> is ignored. By default, it is
+C<lib/$pkg/$subpkg/>.
+
+=item locale_maketext_simple_opts => $hashref
+
+Defaults to:
+
+ { Path => $dir, Style => 'maketext', Decode => 1,
+ Class => $pkg, Subclass => $subpkg }
+
+=back
+
=cut
sub setup {
my $self = shift;
$self->NEXT::setup(@_);
- my $calldir = $self;
- $calldir =~ s#::#/#g;
- my $file = "$calldir.pm";
- my $path = $INC{$file};
- $path =~ s#\.pm$#/I18N#;
- eval <<"";
- package $self;
- import Locale::Maketext::Simple Path => '$path', Export => '_loc', Decode => 1;
+ $self->config->{i18n} ||= {};
+
+ my $pkg = $self->config->{i18n}->{pkg} ||= $self;
+ my $subpkg = $self->config->{i18n}->{subpkg} ||= 'I18N';
- if ($@) {
- $self->log->error(qq/Couldn't initialize i18n "$self\::I18N", "$@"/);
+ my $i18n_dir = $self->config->{i18n}->{dir};
+ if (!$i18n_dir) {
+ # This is deliberately a Unix path for simplicity
+ # Locale::Maketext::Simple remaps to local path
+ (my $app_pm = "$pkg.pm") =~ s{::}{/}gxms;
+ (my $app_dir = $INC{$app_pm}) =~ s{\.pm\z}{}xms;
+ $i18n_dir = File::Spec->catdir($app_dir, $subpkg);
+ $self->config->{i18n}->{dir} = $i18n_dir;
}
- else {
- $self->log->debug(qq/Initialized i18n "$self\::I18N"/) if $self->debug;
+ if (! File::Spec->file_name_is_absolute($i18n_dir)) {
+ $i18n_dir = $self->path_to($i18n_dir)->stringify;
+ }
+
+ my %default_opts = (
+ Path => $i18n_dir,
+ Style => 'maketext',
+ Decode => 1,
+ Class => $pkg,
+ Subclass => $subpkg,
+ );
+ my %opts = (
+ %default_opts,
+ %{ $self->config->{i18n}->{locale_maketext_simple_opts} || {} },
+ );
+
+ Locale::Maketext::Simple->reload_loc();
+ my ($loc, $loc_lang) = Locale::Maketext::Simple->load_loc(%opts);
+ {
+ # Manual export to avoid another eval
+ no strict 'refs'; ## no critic(Strict)
+ *{$pkg . '::_loc'} = $loc || Locale::Maketext::Simple->default_loc(%opts);
+ *{$pkg . '::_loc_lang'} = $loc_lang || sub { 1 };
}
+ $self->log->debug(qq/Initialized i18n "$pkg\::$subpkg"/) if $self->debug;
+
+ if (! $self->config->{i18n}->{installed_languages}) {
+ my %langs;
+ if (opendir my $dir_fh, $i18n_dir) {
+ # Pull root of valid filenames
+ for my $entry (readdir $dir_fh) {
+ my ($lang) = $entry =~ m/\A (\w+)\.(?:pm|po|mo) \z/xms;
+ next if !$lang;
+ next if $lang eq 'i_default';
+ $lang =~ s/_/-/gxms;
+ $langs{$lang} = 1;
+ }
+ closedir $dir_fh;
+ }
+
+ $self->config->{i18n}->{installed_languages} = [ sort keys %langs ];
+ }
+
+ return;
}
=head2 METHODS
@@ -97,8 +184,8 @@
'i-default'
];
}
- no strict 'refs';
- &{ ref($c) . '::_loc_lang' }( @{ $c->{languages} } );
+ no strict 'refs'; ## no critic(Strict)
+ &{ $c->config->{i18n}->{pkg} . '::_loc_lang' }( @{ $c->{languages} } );
return $c->{languages};
}
@@ -110,10 +197,11 @@
sub language {
my $c = shift;
- my $class = ref $c || $c;
- my $lang = ref "$class\::I18N"->get_handle( @{ $c->languages } );
- $lang =~ s/.*:://;
+ my $pkg = $c->config->{i18n}->{pkg};
+ my $subpkg = $c->config->{i18n}->{subpkg};
+ my $lang = ref "$pkg\::$subpkg"->get_handle( @{ $c->languages } );
+ $lang =~ s/.*:://xms;
return $lang;
}
@@ -133,10 +221,27 @@
sub localize {
my $c = shift;
$c->languages;
- no strict 'refs';
- return &{ ref($c) . '::_loc' }( $_[0], @{ $_[1] } )
+ no strict 'refs'; ## no critic(Strict)
+ return &{ $c->config->{i18n}->{pkg} . '::_loc' }( $_[0], @{ $_[1] } )
if ( ref $_[1] eq 'ARRAY' );
- return &{ ref($c) . '::_loc' }(@_);
+ return &{ $c->config->{i18n}->{pkg} . '::_loc' }(@_);
+}
+
+=head3 supported_languages
+
+Returns the list of languages for which there are localizations.
+
+=cut
+
+sub supported_languages {
+ my ( $c, $languages ) = @_;
+
+ if ($languages) {
+ $c->{supported_languages} = $languages;
+ } elsif (!$c->{supported_languages}) {
+ $c->{supported_languages} ||= $c->config->{i18n}->{installed_languages};
+ }
+ return $c->{supported_languages};
}
=head1 SEE ALSO
@@ -150,6 +255,8 @@
Brian Cassidy, C<bricas@cpan.org>
Christian Hansen, C<chansen@cpan.org>
+
+Chris Dolan, C<cdolan@cpan.org>
=head1 COPYRIGHT