<?php
/**
 * patI18n
 *
 * $Id: patI18n.php 4 2007-06-17 20:13:53Z gerd $
 *
 * Modular translation interface
 *
 * @version     0.1.0
 * @package     patI18n
 * @author      gERD Schaufelberger <gerd@php-tools.net>
 * @license     LGPL
 * @link        http://www.php-tools.net
 */

/*
 * Load module base class
 */
if( !class_exists( 'patI18n_Module', false ) ) {
    require dirname( __FILE__ ) . '/patI18n/Module.php';
}

/**
 * patI18n
 *
 * Modular translation interface
 * 
 * Inspired by GNU Gettext {@link http://www.gnu.org/software/gettext/} 
 * and it's PHP implementation, this packages provides an sort of compatible
 * but modular interface for translation.
 * 
 * Both, text domains and plural forms are supported as Gettext does it. The 
 * names of the static functions are the same as in Gettext. This way using
 * it is piece of cake when you are familiar with Gettext. Besides providing
 * the same interface, allows you to use the normal Gettext tools like 
 * "xgettext" to extract to-be-translated strings etc. 
 * 
 * Still, patI18n is not fixed to utilise Gettext at all. The modular design
 * allows to connect any kind of translation tool. Furthermore, you can even 
 * use more than one module at the same time.
 *
 * @version     0.1.0
 * @package     patI18n
 * @author      gERD Schaufelberger <gerd@php-tools.net>
 * @license     LGPL
 * @link        http://www.php-tools.net
 */
class patI18n
{
   /**
    * complete locale name, e.g. "de_DE@euro" or "de_DE.UTF-8"
    */
    const LOCALE_TYPE_COMPLETE = '1';
    
   /**
    * just the language name with variant, like "de_DE"
    */
    const LOCALE_TYPE_LANG = '2';
    
   /**
    * just the short (two) letter language name, like "de"
    */
    const LOCALE_TYPE_SHORT = '4';
    
   /**
    * List of concrete translation modules
    * @var array
    * @see addModule()
    */
    static protected $modules    =   array();

   /**
    * Current locale
    * @var string
    */
    static protected $locale    =   'C';

   /**
    * Add localisation module
    * 
    * Append named module into module chain. The module will be loaded 
    * automatically and configured with the given settings.
    * 
    * @param string $name module name
    * @param string $settings list of configuation options
    * @return bool true on success
    * @todo allow class loader to load from custom module folders
    */
    static public function addModule( $name, $settings = array() )
    {
        $class  =   'patI18n_Module_' . $name;
        if( !class_exists( $class, false ) ) {
            include dirname( __FILE__ ) . '/patI18n/Module/' . $name . '.php';
        }

        $m      =   new $class();
        $m->configure( $settings );

        self::$modules[]    =   $m;
        return true;
    }

   /**
    * Switch to language
    * 
    * This is the replacement for PHP's (@link setLocale()}. This call
    * gets forwared to all modules. 
    * 
    * Each module is expected to return "true". In case one module returns 
    * "false", further processing is canceled. 
    * 
    * @param string $string
    * @return bool true on success
    */
    static public function setLocale( $locale )
    {
        self::$locale   =   $locale;
        foreach( self::$modules as $m ) {
            if( !$m->setLocale( $locale ) ) {                
                return false;
            }
        }
        return true;
    }
    
   /**
    * Simple getter
    * 
    * @param int $type, on of: LOCALE_TYPE_COMPLETE, LOCALE_TYPE_LANG or LOCALE_TYPE_SHORT
    * @return string $locale
    * @todo this is just lazy implementation
    */
    static public function getLocale( $type = self::LOCALE_TYPE_COMPLETE )
    {
        switch( $type ) {
            case self::LOCALE_TYPE_COMPLETE:
                return self::$locale;
                
            case self::LOCALE_TYPE_LANG:
                return substr( self::$locale, 0, 5 );
                
            case self::LOCALE_TYPE_SHORT:
                return substr( self::$locale, 0, 2 );
                
             default:
                break;
        }
        
        // this is not suposed to happen
        throw new Exception( 'The used type is unknown' );                
    }
    
   /**
    * Gettext interface
    * 
    * This is the most simple version. It does neithere support domains nor
    * plural forms.
    * 
    * Again, this is just a forward to each module. The modules will
    * will be called in the same order as they were added. The first module
    * that returns "true" - which means the string was translated, ends 
    * the process - the rest of the modules won't be called at all!
    * 
    * @param string $string To be translated string
    * @return string translated string
    */
    static public function gettext( $string )
    {
        foreach( self::$modules as $m ) {
            if( $m->gettext( $string ) ) { 
                return $string;
            }
        }
        return $string;
    }

   /**
    * Gettext interface using domain
    * 
    * This is pretty much the same as {@link gettext()}. The only difference
    * is that the "domain" is passed to the module as well.    
    * 
    * @param string $domain name of text domain
    * @param string $string To be translated string
    * @return string translated string
    * @see gettext()
    */
    static public function dgettext( $domain, $string )
    {
        foreach( self::$modules as $m ) {
            if( $m->gettext( $string, $domain ) ) { 
                return $string;
            }
        }
        return $string;
    }

   /**
    * Gettext plural version interface
    * 
    * This is pretty much the same as {@link gettext()}, but there are
    * two strings to be translated. The second one is the plural form.
    * 
    * Some languages have more than one form for plural messages dependent 
    * on the count.
    * 
    * @param string $string To be translated string
    * @param string $stringPlural the plural form of the translated string
    * @param int $count The numnber of items the plural should be applied for
    * @return string translated string
    * @see gettext()
    */
    static public function ngettext( $string, $stringPlural, $count )
    {
        foreach( self::$modules as $m ) {
            if( $m->ngettext( $string, $stringPlural, $count ) ) { 
                return $string;
            }
        }
        return $string;
    }
    
   /**
    * Gettext plural version interface using domain
    * 
    * Pretty much the same as {@link ngettext()}, but it requires a "domain"
    * 
    * @param string $domain name of text domain
    * @param string $string To be translated string
    * @param string $stringPlural the plural form of the translated string
    * @param int $count The numnber of items the plural should be applied for
    * @return string translated string
    * @see ngettext()
    */
    static public function dngettext( $domain, $string, $stringPlural, $count )
    {
        foreach( self::$modules as $m ) {
            if( $m->ngettext( $string, $stringPlural, $count, $domain ) ) { 
                return $string;
            }
        }
        return $string;
    }
}
?>