Giving CGI::Application internationalization (I18N) part4

| No Comments | No TrackBacks
Giving CGI::Application internationalization (I18N)

Part 4

After a bit of debugging I finally have the first release of the module ready. All the methods are documented, I've done some manual testing but I still need to bulk out all of the automated tests. I also need to writing documenation on how to create the .po and .mo files to use with this, but I've come across a very useful cross platform app called Poedit which makes it a lot easier.

I'm probably over eager to upload this to CPAN, as it's only version 0.01 but I'm keen to get it up.

With a bit of luck I'll have it uploaded tonight. It's also given me some good material for my next post "Packaging CPAN modules from Windows in Linux Style", as I'm having to do this and I've seen this come up in forums from time to time.

Module code below:-

package CGI::Application::Plugin::I18N;

=head1 NAME

CGI::Application::Plugin::I18N - I18N and L10N methods for CGI::App


    use CGI::Application::Plugin::I18N;

Within your setup, cgiapp_init, cgiapp_prerun or specific runmode routine add
the line



    $self->i18n_config( %options );

%options are the same as for Locale::Maketext::Simple. If none are passed the
following default are used:-

        Path        => "$RealBin/I18N",
        Style        => 'gettext',
        Export        => '_maketext',
        Decode        => 1,
        Encoding    => 'locale',

$RealBin being the folder from which the executed cgi script is running.
B<Note that Export must remain as _maketext for this module to function

For instance if you wanted to use maketext style markup in your lexicons you
would use the line:-

    $self->i18n_config( Style => 'maketext' );

Then use the I<localtext> method to localize text:-

    print $self->localtext( 'Hello World!' );


This module is a wrapper around C<Locale::Maketext::Simple> by Audrey Tang.
It extends the C<CGI::Application> object with variour methods to control the
localization of text. A L</FAQ> is provided with the aim to fill in the gaps.

=head1 Methods

=head2 i18n_config

Runs the initial configuration of C<Locale::Maketext::Simple> and runs it's
import within your calling objects namespace (Your CGI::App class)

=head2 localtext_langs

Sets the current language for localtext output. Usage:-

    $self->localtext_langs( LIST );

LIST must consist of valid language tags as defined in RFC3066. See
C<I18N::LangTags> for more details.
If LIST is ommited then the method will attempt to figure out the users locale
using C<I18N::LangTags::Detect>.

This method will also return the list of language tags as an array reference.

    my $langtags = $self->localtext_langs( LIST );
    print @$langtags;

=head2 localtext_lang

This method returns the currently selected language. This is the tag that was
actually available for use, after searching through the localtext_langs list.
This is the name of the module used in your MyAPP::I18N::XXX namespace (where
XXX is the name of the lexicon used)

    my $lexicon = $self->localtext_lang;

=head2 localtext_lang_tag

This method returns the RFC3066 language tag for the currently selected
language. This differs from the above method which would most likely return
I<en_us> for American English, whereas this method would return I<en-us>.

    my $langtag = $self->localtext_lang_tag;

=head2 localtext

This is the method that actually does the work.

    print $self->localtext( 'Hello World!' );

=head1 FAQ

=head2 How does it all work?

I kept a blog on how I put this module together and all the material I looked
through in order to understand internationalization.

=head2 What is a Lexicon?

Think of it as a kind of hash. Where the text you use (usually english) has a
corrosponding value in the local language. So the 'Hello world' under a German
lexicon would have the value 'Hallo welt'.

=head1 Thanks to:-

C<Catalyst::Plugin::I18N> - The module this one was heavily based on

C<Locale::Maketext::Simple> - Making it possible

C<Locate::Maketext> - Doing all the hard work

C<CGI::Application> - Providing the framework

And all others I haven't yet mentioned.


use strict;
use warnings;
use Carp;

use FindBin qw($RealBin);

use I18N::LangTags ();
use I18N::LangTags::Detect;

require Locale::Maketext::Simple;


require Exporter;
@ISA = qw(Exporter);

@EXPORT = qw (

@EXPORT_OK = qw(

$VERSION = '0.01';

    Path        => "$RealBin/I18N",
    Style       => 'gettext',
    Export      => '_maketext',
    Decode      => 1,
    Encoding    => 'locale',

sub i18n_config {

    my $self = shift;
    my $class = ref $self || $self;
    if ( @_ ) {
        my %newoptions = @_;
        my @valid_options = ("Class","Style","Export","Subclass","Decode","Encoding","Path");
        foreach my $key (keys %newoptions) {
            unless (grep (/^$key$/, @valid_options)) {
                croak( "Invalid option: $key" );
        %DEFAULT_OPTIONS = (%DEFAULT_OPTIONS, %newoptions);

    my $evalcode = qq~
        package $class;
        Locale::Maketext::Simple->import( \%CGI\::Application\::Plugin\::I18N\::DEFAULT_OPTIONS );
    eval $evalcode;

    if ( $@ ) {
        croak( qq~Couldn't initialize i18n, error "$@", code "$evalcode"~ );

sub localtext_langs {
    my $self = shift;
    my @langs = @_;
    if (@langs) {
        $self->{__I18N_LANGS} = \@langs;
    else {
        ### Get CGI query object
        my $q = $self->query();
        $self->{__I18N_LANGS} = [
        ] unless $self->{__I18N_LANGS};
    no strict 'refs';
    &{ ref($self) . '::_maketext_lang' }( @{ $self->{__I18N_LANGS} } );
    return $self->{__I18N_LANGS};

sub localtext_lang {
    my $self = shift;
    my $class = ref $self || $self;

    my $lang = ref "$class\::I18N"->get_handle( @{ $self->localtext_langs } );
    $lang =~ s/.*:://;

    return $lang;

sub localtext_lang_tag {
    my $self = shift;
    my $class = ref $self || $self;

    return "$class\::I18N"->get_handle( @{ $self->localtext_langs } )->language_tag;

sub localtext {
    my $self = shift;
    $self->localtext_langs unless $self->{__I18N_LANGS};
    no strict 'refs';
    return &{ ref($self) . '::_maketext' }( $_[0], @{ $_[1] } ) if ( ref $_[1] eq 'ARRAY' );
    return &{ ref($self) . '::_maketext' }(@_);


No TrackBacks

TrackBack URL:

Leave a comment

About this Entry

This page contains a single entry by Lyle published on January 7, 2009 12:28 AM.

Giving CGI::Application internationalization (I18N) part3 was the previous entry in this blog.

Packaging CPAN modules from Windows in Linux Style is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.