NAME
    Apache::Language - Perl transparent language support for Apache
    modules and mod_perl scripts

SYNOPSIS
      In YourModule.pm:
      
      sub handler {
      my $r = shift;
      use Apache::Language;
      my $lang = Apache::Language->new($extra_args);
      #$lang is now a hash ref that will automacigally pick the right language
      
      print $lang->{'Error01'} if exists $lang->{'Error01'};
      
      foreach ( keys %$lang ){
        print "$_ is " . $lang->{$_};
        }
      
      [...]
      }

DESCRIPTION
    The goal of this module is to provide a simple way for mod_perl
    module writers to include support for multiple language
    requests.

    This is version 0.03, and it's a complete rewrite from the
    ground-up of the previous release. It's still backward-
    compatible with the other releases, but now it's much more
    advanced.

    An Apache::Language object acts like a language-aware hash. It
    stores key/language/values triplets. Using the Accept-Language:
    field sent by the web-client, it can pick the best fit language
    for that specific client. It's usage is transparent and should
    prove to be quite convenient (and hopefully, efficient).

    The method used to store/fetch information is now completely
    modular and will allow easy creation of new storage methods thru
    a simple API (see the API section).

  BASIC USAGE EXAMPLE

    This section will describe the easiest way to start using
    Apache::Language.

    Apache::Language is used to create a hash that will contain
    key/language/value triplets. Say you are building a module that
    prints a few error messages, but since your users speak 3
    different languages, you'd like your module to be nice to them
    and print the messages in their native language.

    For this approach to work, a few things are needed. First, the
    client software (Netscape/IE/lynx, etc.) should send an Accept-
    Language: header telling the webserver what languages it's user
    understands. This might sound simple, but as a web-surfer, did
    you set that language setting in your browser? Most likely, you
    didn't. So the first step is to correctly configure your browser
    and try to make sure your users/visitors will have done the
    same, or they might not get what you want them to read.

    Secondly, you must store the messages you want to display in
    each avaliable languages. For this example, we will use the
    default LanguageHandler Apache::Language::PlainFile that ships
    with this distribution. To do that, suppose your module is named
    Apache::MyModule and it's stored in a file named MyModule.pm.
    You will only need to edit a file named MyModule.dic in the same
    place your module is stored. The format of that file is : (for
    more information see the Apache::Language::PlainFile
    manpage(3)).

     error01:en

     Error Message 01

     error01:fr

     Message d'erreur 01

     error02:en

     Error Message 02

    Once that file contains your error messages, you're all set.
    Just add this to the top of your module:

     use Apache::Language
     my $lang = Apache::Language::new($extra_args)

    Then $lang will be a language-enabled hash reference that you
    can use like this:

     print $lang->{error01}

    That line will print your error message 01 in the best language
    for the client that your module served. Of course, there are a
    lot more things you can do with Apache::Language. All these
    features are explained below.

DETAILLED USAGE
    The key to using Apache::Language is to understand the the data
    retrieving/storing is now done in a manner similar to mod_perl
    content handlers. That's why I called them Language Handlers. A
    language handler is a perl module that is specialized in
    storing/fetching key/language/values triplets.

    Apache::Language simply manages those modules and makes
    interaction with other modules painless. For every request,
    Apache::Language maintains a stack of the LanguageHandlers
    configured for that request's location. Asking each of them in
    order to try finding a value for the requested key that would
    satisfy the client acceptable languages.

    That way you can have a number of language handlers, one looking
    up in a system-wide dictionnary, one looking up in a module-
    specific dictionnary and one looking up a RDBM. Each of them
    would be queried until an acceptable response is found. This
    makes maintaining language definitions pretty versatile and
    configurable.

    With this package is shipped 2 basic LanguageHandlers: the
    Apache::Language::PlainFile manpage and the
    Apache::Language::DBI manpage. Check out their respective man
    pages for more specific information. And more of those
    LanguageHandlers will be shipped in future versions and if you
    need a specific language handling module, simply write your own.
    Read the API section for more information about writing your own
    LanguageHandlers and check the 2 mentionned above, they are nice
    examples.

CONFIGURATION DIRECTIVES
    There are a some configurations directives you can use to
    customize how Apache::Language handles requests.

    LanguageHandler
        This is the main directive. It sets the language handlers
        for a specific location. It's usage is like IndexOptions.
        Meaning it supports +/- notations.

        With a list of handlers without any +/- signs it simply sets
        the handler stack for the current location to those.

        With a list of handlers all with +/- signs, it merges them
        with the parent configuration:

         LanguageHandler Apache::Language::handler1 Apache::Language::handler2
         <Location /test/>
         LanguageHandler +Apache::Language::handler3 -Apache::Language::handler2 
         </Location>

        Will result in a handler stack of
        [Apache::Language::Handler1 , Apache::Language::Handler3]
        for requests in the /test/ directory

        2 things to note though:

        The default handler (Apache::Language::PlainFile) will
        always be the last handler in the stack.

        If a module isn't found, it will be tried again with
        Apache::Language:: prepended to it, so you can write
        LanguageHandler handler2 instead of LanguageHandler
        Apache::Language::handler2

    LanguageForced
        This directive is given a list of languages that should
        exclusively be tried to please the client. This a way to
        mark a certain <Location> as specifically danish, for
        example. If no definition is found for that language, the
        standard 'sorry, no language definition found' message is
        printed.

    LanguageDefault
        Provided with a list of languages, this directives sets the
        default languages it should try to send if none of the
        languages requested by the client can be found.

    DefaultLanguage
        This is a not an Apache::Language directive, but in the
        absence of a LanguageDefault directive, that setting will be
        used to set the default languages

    LanguageDebug
        This will set the level of debugging information sent to the
        apachelog. Values ranges from 0-4. 4 being very noisy and 0
        very quiet. 0 will still warn you about fatal errors. A
        setting of -1 simply doesn't log anything. Nothing.

STATUS Handler
    If you have the Apache::Status module loaded before
    Apache::Language, a custom status module will be installed.
    Usually accessed thru /perl-status, it will give you an
    Apache::Language menu with quite a few bits of interesting
    information about Apache::Language status.

API
    The Apache::Language API is pretty simple and might evolve in
    future versions. The first argument to all function calls will
    be the class name of the handler.

    The API was developped to provide for: 1. abstraction of the
    data storage/retrieval and 2. an easy way for other developpers
    to write new containers without having to modify the whole
    package.

    If you want to write your own Language::Handler, read on. You
    might also find more interesting information by looking at the
    couple of LanguageHandlers distributed as part of the
    Apache::Language package. I also think that new LanguageHandlers
    should be named under the Apache::Language::* namaspace for
    simplicity. As of this writing I am have quite a few other
    LanguageHandlers on the way, so if you are planning on writing a
    new one, get in touch with me before, maybe I already have some
    work done I'd be happy to send you.

    There is one thing that you must understand before writing your
    own LanguageHandler. It's how Apache::Language caches
    information about LanguageHandlers. For performance reasons, and
    since most mod_perl scripts/modules will want to have their own
    language definitions, information is cached on a per-
    Module/script basis. This means that suppose the module
    Apache::MyHandler uses Apache::Language, all LanguageHandlers
    serving requests for Apache::MyHandler will be given access to a
    cache ($data) that's specific to Apache::MyHandler and to
    another cache that's specific to Apache::MyHandler and the
    current LanguageHandler. In the case that a certain handler
    doesn't want this degree of encapsulation (i.e. a dictionnary of
    common used error messages, system wide) it's free to maintain
    it's own cache (in it's namespace) and disregard the Module &
    Handler specific cache. That cache is merely provided so
    LanguageHandler writers won't have to deal with per Module cache
    themselves. But you can do without it.

    This is what a small dump of the cache might look like : (For
    the visual types)

    #Cached information for the mod_perl Handler Apache::MyHandler1
    $VAR1 = 'Apache::MyHandler1'; $VAR2 = bless( { #current
    LanguageHandler stack 'Handlers' => [
    'Apache::Language::Handler1', 'Apache::Language::Handler2' ],
    'Request' => [Apache $r object] #Filename of the Calling package
    'Filename' => '/usr/lib/perl5/Apache/MyHandler1.pm', #Language
    requested by the client 'Lang' => [ 'en', 'fr-ca', 'fr' ],
    #Package name of the Calling package 'Package' =>
    'Apache::MyHandler1', #Specific data for LanguageHandler
    Apache::Language::Handler1 'Apache::Language::Handler1' => { #Is
    the LanguageHandler a listable one? 'listable' => 1, 'DATA' => {
    #this is the $cfg object passed to the handler #it's completely
    private to the Language::Handler 'dbname' => 'DBI::Pg', 'query'
    => 'select value from language where key=? and lang=?' }, #Is
    the LanguageHandler a storable one? 'storable' => 1 }, #Specific
    data for LanguageHandler Apache::Language::Handler2
    'Apache::Language::Handler2' => { #Is the LanguageHandler a
    listable one? 'listable' => 0, 'DATA' => { #this is the $cfg
    object passed to the handler #it's completely private to the
    Language::Handler 'option1' => 'read/write', 'debug' => 1 }, #Is
    the LanguageHandler a storable one? 'storable' => 1 }, 'Config'
    => [Opaque structure for directory configuration]

       }, 'Apache::Language' );

    #Cached information for the mod_perl Handler Apache::MyHandler2
    $VAR3 = 'Apache::MyHandler2'; $VAR4 = bless( { #current
    LanguageHandler stack 'Handlers' => [
    'Apache::Language::Handler2' ], 'Request' => [Apache $r object]
    #Filename of the Calling package 'Filename' =>
    '/usr/lib/perl5/Apache/MyHandler1.pm', #Language requested by
    the client 'Lang' => [ 'en', 'fr-ca', 'fr' ], #Package name of
    the Calling package 'Package' => 'Apache::MyHandler1',

         #Specific data for LanguageHandler Apache::Language::Handler2     
         'Apache::Language::Handler2' => {
              #Is the LanguageHandler a listable one?
              'listable' => 0,  
              'DATA' => {  #this is the $cfg object passed to the handler
                           #it's completely private to the Language::Handler
                          'dbname' => 'DBI::mysql',
                          'query' => 'select value from language2 where key=? and lang=?'
                        },
              #Is the LanguageHandler a storable one?
              'storable' => 1  
              },
         'Config' =>  [Opaque structure for directory configuration]
       }, 'Apache::Language' );

  API data structures

    All functions calls to LanguageHandlers are passed these 2 data
    structures as the second and third arguments. The first argument
    always being the class name of the LanguageHandler.

    $data

    This is the data associated with the particular http request.
    It's also unique to the currently served Module, so it can be
    used to store some information, but since Apache::Language
    stores a few things of itself there, be carefull to use keys
    unique to your module (i.e. $data-
    >{"Apache::Language::YourHandler::key"} = "private data") It's
    an Apache::Language object with the following calls avaliable:

    lang()
        returns a preference-sorted list of the language the clients
        requested.

    handlers()
        returns the current LanguageHandler stack (list)

    request()
        returns the current request (Apache::Request)

    package()
        returns the name of the package handling the request

    filename()
        returns the filename of the package handling the request

    extra_args()
        returns a reference to a list of what was passed to the new
        constructor

    $cfg

    This is a private storage space for the current Handler.
    Handlers can store whatever they want there. That data will be
    preserved for this Handler/(Calling module/package) pair. Look
    in Apache::Language::PlainFile for a good exapmle of using that.

  Required API functions

    initialize ($data, $cfg)
        This is called for the first request so a LanguageHandler
        can do it's initialization. This will also be called each
        time a call to the modified() function informs
        Apache::Language that something has changed.

        It has the opportnity to examine the requesting conditions
        and if it chooses not to be involved in the handling of that
        specific requesting Module, it should return anything but
        L_OK. That way it will be removed from the LanguageHandler
        stack for that Module and therefore will not be called for
        that Module anymore

    modified ($data, $cfg)
        This is called for each request to know if the datasource
        changed and should be re-initialized. It should return true
        if something is modified and re-initialization is needed.

    fetch ($data, $cfg, $key, $lang)
        This function can be called in 2 ways. First if there $lang
        is defined, the LanguageHandler is requested to produce that
        exact language version for the key $key. This happends if a
        user requested a specific language with $lang->{key/lang} or
        to find an entry for the default language if everything else
        failed to produce a value. It should return undef if
        unknown.

        Second, if $lang is undefined, this means that the Handler
        should try to return the best possible match for the current
        request. $data->lang will return the list of language the
        client understands, sorted preferred first. But since
        language-tags allow for variants and dialects, it's now
        always easy for a module to determine what language it
        should pick if it knows 'en-us' and 'en' and the clients
        understands 'en-ca' and 'de'.

    Everything else
        If a call is made to an unknown routine, Apache::Language
        will try to call it on each Handler in the current handler
        stack until someone can deal with that function call. The
        call is made with ($data, $cfg, @args) as arguments. @args
        being the arguments passed to that function by the calling
        user. Remember that to get at the new() arguments, you just
        have to do a @args = @{$data->extra_args()};

        To simplyfy some things, there is the helper function $data-
        >best_lang described below.

  Helper API Functions

    $data->best_lang(@avaliable_language)
        This is the generic best-language picking routine. This
        function given the list of known languages to the handler,
        returns the best language based on the client's request.

        For example, a simple handler could handle queries like
        this:

         sub fetch {
            my ($class, $data, $cfg, $key, $lang) = @_; 
            #the language information is kept in the $cfg hash

            #if a specific language is asked for:
            return $cfg->{$key}{$lang} if $lang;  

            #we must choose the right language ourself.
            #(keys % {$cfg->{$key}}) produces the list of languages in wich $key is known     
            my $variant = $data->best_lang(keys % {$cfg->{$key}});
            
            #$variant now holds the best pick for us, or undef if nothing matches..
            return $cfg->{$key}{$variant} if $variant;
            
            #give up
            return undef;     
         }

  Optionnal API Functions (store)

    store ($data, $cfg ,$key, $lang, $value)

    If this function is present, the handler will be makred as
    'storable' and any assignments to the language hash will call
    this function. Storing in a language hash should be done by
    providing a key/language pair as key to the hash (ie. $lang-
    >{key01/en-us} = "string"). This should return L_OK on success
    and L_ERROR in case of an error.

  Optionnal API Functions (firstkey/nextkey)

    This are functions necessary to make the Language hash listable
    (i.e. keys and each). The tricky thing is that since
    LanguageHandlers are stackable and often each have a change at
    the request, listing a specific language hash is ambiguious. The
    way it's handled is straightforward. The first listable module
    that returns something else than undef on the call to firstkey
    is the chosen one. It will be used to list the hash until it's
    nextkey function returns undef, and all subsequent list request
    will be handled by that module.

    It should be noted that I don't really know what might happend
    in the case of recursive/re-entrant lists, so if you don't want
    to spend time fixing it yourself, be carefull about that.

    These functions follow exactly the same rules as the generic
    TIEHASH mechanism. So, for more information see the perltie
    manpage

    firstkey ($data, $cfg)
        This will be called first when a list request is
        encountered. It should return the first key of the hash and
        set up things for the nextkey calls.

    nextkey ($data, $cfg, $lastkey)
        This will be called once the listing of the language hash
        has started. Make sure it will eventually return undef to
        mark the end of the list or else you will end up in an
        infinite loop.

TODO
    * Find and correct bugs.
    * Find new features to add.
SEE ALSO
    perl(1), the Apache manpage(3), the Apache::Language::Constants
    manpage(3), and all the Apache::Language::* manpage.

SUPPORT
    Please send any questions or comments to the Apache modperl
    mailing list <modperl@apache.org> or to me at
    <gozer@ectoplasm.dyndns.com>

NOTES
    This code was made possible by :

    *   Doug MacEachern <dougm@pobox.com> Creator of mod_perl. That
        should mean enough.

    *   Andreas Koenig <koenig@kulturbox.de> The one I got the idea from
        in the first place.

    *   The mod_perl mailing-list at <modperl@apache.org> for all your
        mod_perl related problems.

AUTHOR
    Philippe M. Chiasson <gozer@ectoplasm.dyndns.com>

VERSION
    This is revision $Id: Language.pod,v 1.2 1999/04/18 22:02:37
    gozer Exp $

COPYRIGHT
    Copyright (c) 1999 Philippe M. Chiasson. All rights reserved.
    This program is free software, you can redistribute it and/or
    modify it under the same terms as Perl itself.