NAME
    Locale::VersionedMessages - handle all aspects of the localization
    process

SYNOPSIS
      use Locale::VersionedMessages

      $obj     = new Locale::VersionedMessages;
      $vers    = $obj->version();
      $obj->search(LOCALE_LIST);

DESCRIPTION
    Although several modules exist for handling internationalization and
    localization of a prgram, they are missing functionality for dealing
    with all of the functions to perform the task fully. Existing modules
    work fine with respect to a programmer who wants to access localized
    messages, but the modules do not contain the necessary functions to
    maintain those messages.

    This module (and the programs that are distributed with it) form a
    complete package for handling the localization problem.

    At the heart of the localization problem, you have a set of messages.
    These messages may be translated into any number of locales, and a
    programmer can then look up the appropriate message, as it would appear
    in the desired locale.

    Any number of sets of messages may be used by a program. A set of
    messages is best thought of as a set of related messages which might be
    used by any number of programs. For example, one set of messages might
    be I/O error messages encountered when working with files. Another set
    might be the messages specific to one particular program.

    Each set of messages can be translated into the language for any number
    of locales. Ideally, all messages would be translated into all locales,
    but that is often not the case. However, every set of messages has a
    default locale (which may not be the same across all sets of messages)
    which MUST have all of the messages in it.

    This allows you to look up a message in either the locale you are
    working with, or the default locale if it is not available there.

    Unlike most existing localization modules, this module keeps track of
    the version of every message in every locale. Although this information
    is not typically useful to those programmers who are simply looking up
    messages in the table, it is extremely useful to those who are
    responsible for translating and maintaing the messages.

METHODS
    The following methods are available:

    new
           $obj = new Locale::VersionedMessages;

        This creates a new Locale::VersionedMessages object.

    version
           use Locale::VersionedMessages;
           $obj = new Locale::VersionedMessages;
           $vers = $obj->version();

        Check the module version.

    err
           $err = $obj->err();

        This returns any error message set during the previous operation.

    set
           $obj->set(SET0 [,SET1,SET2,...]);

        This loads any number of message sets into the object. You can only
        look up messages from sets that have been loaded.

           @set = $obj->set();

        This returns the names of the message sets that have been loaded.
        SETi is a string containing alphanumeric and underscore characters.

    query_set_default
    query_set_locales
    query_set_msgid
        These return information about a message set.

           $locale = $obj->query_set_default();

        returns the default locale.

           @locale = $obj->query_set_locales();

        returns the list of all locales for which this message set is
        defined.

           @msgid = $obj->query_set_msgid();

        returns a list of all message IDs in this set of messages. The
        message ID is the label used in the program to access a message.

    search
        This method is used to specify the search order of the locales.

        By default, all messages are returned in the default locale of the
        message set (which may not be the same across message sets), but you
        can change this using these methods.

           $obj->search(LOCALE0 [,LOCALE1,LOCALE2,...]);

        This specifies the global search order. This is the default search
        order of locales used for all message sets. This specifies that, in
        all message sets, the default is to use LOCALE0, followed by
        LOCALE1, LOCALE2, etc.

        If the message is not found in any of the locales, the default
        locale for the set will be used.

        The global search order can be overridden on a per-set basis.

           $obj->search();

        This erases the global default search order.

           $obj->search(SET, LOCALE0 [,LOCALE1,LOCALE2,...]);

        This specifies the search order for the given set, overriding the
        global default search order. It is not necessary that all of the
        locales actually have translations. Any that don't will be silently
        ignored.

        If a message is not found in any of these locales, the default
        locale for the message set will be used.

           $obj->search(SET);

        This erases the search order for the given set, so the global search
        order will be used.

        For example:

           $obj->search('BUTTONS','en','en_US','en_GB');

        would looke for a messages in the 'BUTTONS' set in the locales:
        'en', 'en_US', and 'en_GB' in that order. If a message were not
        found in any of those three, the default locale would be used.

    query_search
           @locale = $obj->query_search();
           @locale = $obj->query_search(SET);

        This returns the global search order or the search order for the
        set.

        In the second call, the global search order is NOT returned if the
        set-specific search order is not set.

    message
           $text           = $obj(SET, MSGID [,LOCALE] [,VALUES]);
           ($text,$locale) = $obj(SET, MSGID [,LOCALE] [,VALUES]);

        This method is used to look up a message in the given set and
        substitutes in VALUES (described below in MESSAGE SUBSTITUTIONS). If
        LOCALE is present, it only looks up the message in that locale. By
        default, it will look in the search order for that set.

        If the message is not found, $text will be the empty string.

        In list context, the text will be returned along with the name of
        the locale in which the message was found.

        If any error occurs, an empty string will be returned for $text.

    query_msg_locales
    query_msg_vers
        These return information about a specific message.

           @locale = $obj->query_msg_locales(SET, MSGID);

        returns a list of all locales for which this message is defined. The
        first one will be the default locale.

           $vers = $obj->query_msg_vers(SET, MSGID [,LOCALE]);

        returns the version of the message in the given locale. If LOCALE is
        not given, it defaults to the default locale. If the message is not
        defined in the locale, a version of 0 is returned.

MESSAGE SUBSTITUTIONS
    When a message is defined, it can have values that will be passed in
    which can be inserted into the message.

    Unlike most localization tool kits, the values are passed in by name,
    rather than position in a list, so the substitution looks a bit
    different than other tool kits.

    When a message is initially defined, two pieces of information are
    required: the message ID and a list of substitution variables. Other
    information (such as a description of the message) may also be provided,
    but is not relevant to message substitution.

    If one of the substition variables is named 'foo', then anywhere in the
    message, I can include '[foo...]' and that portion of the message will
    be replaced based on the value of foo that is passed in.

    The syntax of the substitution string can be any of the following:

    [foo]
        In it's simplest form, the value is simply inserted into the string.
        For example, if the text is defined (in the default lexicon) as:

           Set:        Set1
           Message ID: Foo value [foo]
           Text:       The value of foo is [foo].

        Then:

           $obj->message('Set1','Foo value [foo]',
                         'foo' => 'bar');
              => 'The value of foo is bar.

    [foo:FORMAT]
        The value can be formatted using standard sprintf formats. Only
        simple formats are allowed, so FORMAT can be something like '%.3f'
        but not 'the number %3d'. To be exact, FORMAT must be any valid
        format that can be handled by sprintf that takes exactly one
        argument, so something like %% is not allowed, but any %d format is.

           Set:        Set1
           Message ID: Foo value [foo]
           Text:       The value of foo is >[foo:%5s]<.

           $obj->message('Set1','Foo value [foo]',
                         'foo' => 'bar');
              => 'The value of foo is >  bar<.

    [foo:quant ...] or [foo:quant:FORMAT ...]
        This is for handling plural elements. These two forms are identical
        except that the number will be formatted using a sprintf format in
        the second case.

        The general form of this is:

           [VAL:quant [COND1] [STRING1] [COND2] [STRING2] ... [DEFAULT_STRING]]

        Each CONDi is a string involving a correctly specified numerical
        test. It should be noted that the tests are NOT passed to the perl
        interpreter (via eval), so the full perl syntax is not supported.
        Since tests are specified in user (i.e. translator) defined files,
        passing portions of these files to eval would represent a security
        risk, so instead, the condition strings are manually parsed, and
        only a limited syntax is supported. However, the sytax should be
        flexible enough to handle all real-life cases.

        A condition can be a simple test. Simple tests are all of one of the
        forms:

           NUM <  NUM
           NUM <= NUM
           NUM == NUM
           NUM >= NUM
           NUM >  NUM
           NUM != NUM

        and each NUM can be:

           _VAL
           _VAL % DIGITS
           DIGITS

        Note that there are no signs allowed... only positive integers are
        allowed. Also, parentheses are not allowed inside a simple test
        (though the simple test can be enclosed in parentheses).

        Simple tests can also be combined using parentheses and the two
        operators '&&' and '||'.

        If COND1 is met, then STRING1 is used. If COND2 is met, then STRING2
        is used. If none of the conditions are met, then the DEFAULT_STRING
        is met.

        The DEFAULT_STRING is required, and at least one COND and STRING
        should be included (though they are not strictly required... if they
        are not present,t hen the DEFAULT_STRING will always be used.

        An actual example might be:

           Set:        Set1
           Message ID: Number of oranges [n]
           Text:       I have [n:quant [_n>1] [_n oranges] [_n==1] [1 orange] [no oranges]].

        and:

           $obj->message('Set1','Number of oranges [n]',1);
              => 'I have 1 orange.'

           $obj->message('Set1','Number of oranges [n]',3);
              => 'I have 3 oranges.'

           $obj->message('Set1','Number of oranges [n]',0);
              => 'I have no oranges.'

        Note that all conditions and strings are enclosed in square
        brackets, and that none of the strings may include square brackets
        in them. Also note that it is not required that '_VAL' be included
        in every one of the strings. It can be included zero, one, or even
        multiple times if desired.

    Most whitespace is ignored, so the following are quivalent:

       [foo]
       [ foo ]

    as are:

       [foo:FORMAT]
       [ foo : FORMAT ]

KNOWN PROBLEMS
    None at this point.

SEE ALSO
    Locale::VersionedMessages::Overview An overview of the
    internationalization problem with a comparison to other Locale::*
    modules

    lm_admin A command-line tool for creating and maintaing sets of messages
    and their translation tables.

LICENSE
    This script is free software; you can redistribute it and/or modify it
    under the same terms as Perl itself.

AUTHOR
    Sullivan Beck (sbeck@cpan.org)

