Implement Horde_Translation as static per-library wrapper.
authorJan Schneider <jan@horde.org>
Fri, 22 Oct 2010 14:10:16 +0000 (16:10 +0200)
committerJan Schneider <jan@horde.org>
Fri, 22 Oct 2010 17:27:03 +0000 (19:27 +0200)
framework/Translation/lib/Horde/Translation.php
framework/Translation/lib/Horde/Translation/Exception.php [new file with mode: 0644]
framework/Translation/lib/Horde/Translation/Gettext.php [deleted file]
framework/Translation/lib/Horde/Translation/Handler.php [new file with mode: 0644]
framework/Translation/lib/Horde/Translation/Handler/Gettext.php [new file with mode: 0644]
framework/Translation/package.xml
framework/Translation/test/Horde/Translation/GettextTest.php
framework/Translation/test/Horde/Translation/TestBase.php [new file with mode: 0644]
framework/Translation/test/Horde/Translation/WrapperTest.php [new file with mode: 0644]

index 257e9bc..4d9cf5d 100644 (file)
@@ -9,15 +9,74 @@
  */
 
 /**
- * The Horde_Translation interface defines the interface for any classes
- * providing translations.
+ * Horde_Translation is the base class for any translation wrapper classes in
+ * libraries that want to utilize the Horde_Translation library for
+ * translations.
  *
  * @author  Jan Schneider <jan@horde.org>
  * @package Translation
  */
-interface Horde_Translation
+abstract class Horde_Translation
 {
     /**
+     * The translation domain, e.g. the library name, for the default gettext
+     * handler.
+     *
+     * @var string
+     */
+    static protected $_domain;
+
+    /**
+     * The relative path to the translations for the default gettext handler.
+     *
+     * This path is relative to the
+     *
+     * @var string
+     */
+    static protected $_directory;
+
+    /**
+     * The handler providing the actual translations.
+     *
+     * @var Horde_Translation_Handler
+     */
+    static protected $_handler;
+
+    /**
+     * Loads a translation handler class pointing to the library's translations
+     * and assigns it to $_handler.
+     *
+     * @param string $handlerClass  The name of a class implementing the
+     *                              Horde_Translation_Handler interface.
+     */
+    static public function loadHandler($handlerClass)
+    {
+        if (!self::$_domain || !self::$_directory) {
+            throw new Horde_Translation_Exception('The domain and directory properties must be set by the class that extends Horde_Translation.');
+        }
+        $backtrace = debug_backtrace();
+        $directory = dirname($backtrace[1]['file']) . '/' . self::$_directory;
+        self::setHandler(new $handlerClass(self::$_domain, $directory));
+    }
+
+    /**
+     * Assigns a translation handler object to $_handler.
+     *
+     * Type hinting isn't used on purpose. You should extend a custom
+     * translation handler passed here from the Horde_Translation interface,
+     * but technically it's sufficient if you provide the API of that
+     * interface.
+     *
+     * @param Horde_Translation_Handler $handler  An object implementing the
+     *                                            Horde_Translation_Handler
+     *                                            interface.
+     */
+    static public function setHandler($handler)
+    {
+        self::$_handler = $handler;
+    }
+
+    /**
      * Returns the translation of a message.
      *
      * @var string $message  The string to translate.
@@ -25,7 +84,13 @@ interface Horde_Translation
      * @return string  The string translation, or the original string if no
      *                 translation exists.
      */
-    public function t($message);
+    static public function t($message)
+    {
+        if (!self::$_handler) {
+            self::loadHandler('Horde_Translation_Handler_Gettext');
+        }
+        return self::$_handler->t($message);
+    }
 
     /**
      * Returns the plural translation of a message.
@@ -37,5 +102,11 @@ interface Horde_Translation
      * @return string  The string translation, or the original string if no
      *                 translation exists.
      */
-    public function ngettext($singular, $plural, $number);
+    static public function ngettext($singular, $plural, $number)
+    {
+        if (!self::$_handler) {
+            self::loadHandler();
+        }
+        return self::$_handler->ngettext($singular, $plural, $number);
+    }
 }
diff --git a/framework/Translation/lib/Horde/Translation/Exception.php b/framework/Translation/lib/Horde/Translation/Exception.php
new file mode 100644 (file)
index 0000000..237fa48
--- /dev/null
@@ -0,0 +1,13 @@
+<?php
+/**
+ * Exception class for Horde_Translation.
+ *
+ * Copyright 2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @author  Jan Schneider <jan@horde.org>
+ * @package Translation
+ */
+class Horde_Translation_Exception extends Horde_Exception { }
diff --git a/framework/Translation/lib/Horde/Translation/Gettext.php b/framework/Translation/lib/Horde/Translation/Gettext.php
deleted file mode 100644 (file)
index a5078db..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-<?php
-/**
- * @package Translation
- *
- * Copyright 2010 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (LGPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
- */
-
-/**
- * The Horde_Translation_Gettext provides translations through the gettext
- * extension, but fails gracefully if gettext is not installed.
- *
- * @author  Jan Schneider <jan@horde.org>
- * @package Translation
- */
-class Horde_Translation_Gettext implements Horde_Translation
-{
-    /**
-     * The translation domain, e.g. package name.
-     *
-     * @var string
-     */
-    protected $_domain;
-
-    /**
-     * Whether the gettext extension is installed.
-     *
-     * @var boolean
-     */
-    protected $_gettext;
-
-    /**
-     * Constructor.
-     *
-     * @param string $domain  The translation domain, e.g. package name.
-     * @param string $path    The path to the gettext catalog.
-     */
-    public function __construct($domain, $path)
-    {
-        if (!is_dir($path)) {
-            throw new InvalidArgumentException('$path is not a directory');
-        }
-        $this->_gettext = function_exists('_');
-        if (!$this->_gettext) {
-            return;
-        }
-        $this->_domain = $domain;
-        bindtextdomain($this->_domain, $path);
-    }
-
-    /**
-     * Returns the translation of a message.
-     *
-     * @param string $message  The string to translate.
-     *
-     * @return string  The string translation, or the original string if no
-     *                 translation exists.
-     */
-    public function t($message)
-    {
-        return $this->_gettext ? dgettext($this->_domain, $message) : $message;
-    }
-
-    /**
-     * Returns the plural translation of a message.
-     *
-     * @param string $singular  The singular version to translate.
-     * @param string $plural    The plural version to translate.
-     * @param integer $number   The number that determines singular vs. plural.
-     *
-     * @return string  The string translation, or the original string if no
-     *                 translation exists.
-     */
-    public function ngettext($singular, $plural, $number)
-    {
-        return $this->_gettext
-          ? dngettext($this->_domain, $singular, $plural, $number)
-          : ($number > 1 ? $plural : $singular);
-    }
-}
diff --git a/framework/Translation/lib/Horde/Translation/Handler.php b/framework/Translation/lib/Horde/Translation/Handler.php
new file mode 100644 (file)
index 0000000..1ba35f5
--- /dev/null
@@ -0,0 +1,41 @@
+<?php
+/**
+ * @package Translation
+ *
+ * Copyright 2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ */
+
+/**
+ * The Horde_Translation_Handler interface defines the interface for any
+ * classes providing translations.
+ *
+ * @author  Jan Schneider <jan@horde.org>
+ * @package Translation
+ */
+interface Horde_Translation_Handler
+{
+    /**
+     * Returns the translation of a message.
+     *
+     * @var string $message  The string to translate.
+     *
+     * @return string  The string translation, or the original string if no
+     *                 translation exists.
+     */
+    public function t($message);
+
+    /**
+     * Returns the plural translation of a message.
+     *
+     * @param string $singular  The singular version to translate.
+     * @param string $plural    The plural version to translate.
+     * @param integer $number   The number that determines singular vs. plural.
+     *
+     * @return string  The string translation, or the original string if no
+     *                 translation exists.
+     */
+    public function ngettext($singular, $plural, $number);
+}
diff --git a/framework/Translation/lib/Horde/Translation/Handler/Gettext.php b/framework/Translation/lib/Horde/Translation/Handler/Gettext.php
new file mode 100644 (file)
index 0000000..18364ae
--- /dev/null
@@ -0,0 +1,82 @@
+<?php
+/**
+ * @package Translation
+ *
+ * Copyright 2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ */
+
+/**
+ * The Horde_Translation_Handler_Gettext provides translations through the
+ * gettext extension, but fails gracefully if gettext is not installed.
+ *
+ * @author  Jan Schneider <jan@horde.org>
+ * @package Translation
+ */
+class Horde_Translation_Handler_Gettext implements Horde_Translation_Handler
+{
+    /**
+     * The translation domain, e.g. package name.
+     *
+     * @var string
+     */
+    protected $_domain;
+
+    /**
+     * Whether the gettext extension is installed.
+     *
+     * @var boolean
+     */
+    protected $_gettext;
+
+    /**
+     * Constructor.
+     *
+     * @param string $domain  The translation domain, e.g. package name.
+     * @param string $path    The path to the gettext catalog.
+     */
+    public function __construct($domain, $path)
+    {
+        if (!is_dir($path)) {
+            throw new InvalidArgumentException('$path is not a directory');
+        }
+        $this->_gettext = function_exists('_');
+        if (!$this->_gettext) {
+            return;
+        }
+        $this->_domain = $domain;
+        bindtextdomain($this->_domain, $path);
+    }
+
+    /**
+     * Returns the translation of a message.
+     *
+     * @param string $message  The string to translate.
+     *
+     * @return string  The string translation, or the original string if no
+     *                 translation exists.
+     */
+    public function t($message)
+    {
+        return $this->_gettext ? dgettext($this->_domain, $message) : $message;
+    }
+
+    /**
+     * Returns the plural translation of a message.
+     *
+     * @param string $singular  The singular version to translate.
+     * @param string $plural    The plural version to translate.
+     * @param integer $number   The number that determines singular vs. plural.
+     *
+     * @return string  The string translation, or the original string if no
+     *                 translation exists.
+     */
+    public function ngettext($singular, $plural, $number)
+    {
+        return $this->_gettext
+          ? dngettext($this->_domain, $singular, $plural, $number)
+          : ($number > 1 ? $plural : $singular);
+    }
+}
index 6ab343e..005dac5 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<package packagerversion="1.9.0" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">
+<package packagerversion="1.9.1" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">
  <name>Translation</name>
  <channel>pear.horde.org</channel>
  <summary>Horde translation library</summary>
@@ -10,8 +10,8 @@
   <email>jan@horde.org</email>
   <active>yes</active>
  </lead>
- <date>2010-10-05</date>
- <time>13:12:56</time>
+ <date>2010-10-22</date>
+ <time>16:08:10</time>
  <version>
   <release>0.1.0</release>
   <api>0.1.0</api>
    <dir name="lib">
     <dir name="Horde">
      <dir name="Translation">
-      <file name="Gettext.php" role="php" />
-     </dir> <!-- //lib/Horde/Translation -->
+      <dir name="Handler">
+       <file name="Gettext.php" role="php" />
+      </dir> <!-- /lib/Horde/Translation/Handler -->
+      <file name="Exception.php" role="php" />
+      <file name="Handler.php" role="php" />
+     </dir> <!-- /lib/Horde/Translation -->
      <file name="Translation.php" role="php" />
-    </dir> <!-- //lib/Horde -->
-   </dir> <!-- //lib -->
+    </dir> <!-- /lib/Horde -->
+   </dir> <!-- /lib -->
+   <dir name="test">
+    <dir name="Horde">
+     <dir name="Translation">
+      <dir name="locale">
+       <dir name="de">
+        <dir name="LC_MESSAGES">
+         <file name="Horde_Other.mo" role="test" />
+         <file name="Horde_Other.po" role="test" />
+         <file name="Horde_Translation.mo" role="test" />
+         <file name="Horde_Translation.po" role="test" />
+        </dir> <!-- /test/Horde/Translation/locale/de/LC_MESSAGES -->
+       </dir> <!-- /test/Horde/Translation/locale/de -->
+      </dir> <!-- /test/Horde/Translation/locale -->
+      <file name="AllTests.php" role="test" />
+      <file name="GettextTest.php" role="test" />
+      <file name="TestBase.php" role="test" />
+      <file name="WrapperTest.php" role="test" />
+     </dir> <!-- /test/Horde/Translation -->
+    </dir> <!-- /test/Horde -->
+   </dir> <!-- /test -->
   </dir> <!-- / -->
  </contents>
  <dependencies>
  <phprelease>
   <filelist>
    <install as="Horde/Translation.php" name="lib/Horde/Translation.php" />
-   <install as="Horde/Translation/Gettext.php" name="lib/Horde/Translation/Gettext.php" />
+   <install as="Horde/Translation/Exception.php" name="lib/Horde/Translation/Exception.php" />
+   <install as="Horde/Translation/Handler.php" name="lib/Horde/Translation/Handler.php" />
+   <install as="Horde/Translation/Handler/Gettext.php" name="lib/Horde/Translation/Handler/Gettext.php" />
+   <install as="Horde/Translation/AllTests.php" name="test/Horde/Translation/AllTests.php" />
+   <install as="Horde/Translation/GettextTest.php" name="test/Horde/Translation/GettextTest.php" />
+   <install as="Horde/Translation/TestBase.php" name="test/Horde/Translation/TestBase.php" />
+   <install as="Horde/Translation/WrapperTest.php" name="test/Horde/Translation/WrapperTest.php" />
+   <install as="Horde/Translation/locale/de/LC_MESSAGES/Horde_Other.mo" name="test/Horde/Translation/locale/de/LC_MESSAGES/Horde_Other.mo" />
+   <install as="Horde/Translation/locale/de/LC_MESSAGES/Horde_Other.po" name="test/Horde/Translation/locale/de/LC_MESSAGES/Horde_Other.po" />
+   <install as="Horde/Translation/locale/de/LC_MESSAGES/Horde_Translation.mo" name="test/Horde/Translation/locale/de/LC_MESSAGES/Horde_Translation.mo" />
+   <install as="Horde/Translation/locale/de/LC_MESSAGES/Horde_Translation.po" name="test/Horde/Translation/locale/de/LC_MESSAGES/Horde_Translation.po" />
   </filelist>
  </phprelease>
  <changelog>
     <release>beta</release>
     <api>beta</api>
    </stability>
-   <date>2010-10-05</date>
+   <date>2010-10-22</date>
    <license uri="http://www.gnu.org/copyleft/lesser.html">LGPL</license>
    <notes>
 * Initial release.
index bc3c327..959063f 100644 (file)
@@ -1,4 +1,7 @@
 <?php
+
+require_once dirname(__FILE__) . '/TestBase.php';
+
 /**
  * @author     Jan Schneider <jan@horde.org>
  * @license    http://www.fsf.org/copyleft/lgpl.html LGPL
@@ -6,28 +9,16 @@
  * @package    Translation
  * @subpackage UnitTests
  */
-
-class Horde_Translation_GettextTest extends PHPUnit_Framework_TestCase
+class Horde_Translation_GettextTest extends Horde_Translation_TestBase
 {
     private $_dict;
     private $_otherDict;
-    private $_env;
 
     public function setUp()
     {
-        try {
-            $this->setLocale(LC_ALL, 'de_DE.UTF-8');
-        } catch (PHPUnit_Framework_Exception $e) {
-            $this->markTestSkipped('Setting the locale failed. de_DE.UTF-8 might not be supported.');
-        }
-        $this->_setEnv('de_DE.UTF-8');
-        $this->_dict = new Horde_Translation_Gettext('Horde_Translation', dirname(__FILE__) . '/locale');
-        $this->_otherDict = new Horde_Translation_Gettext('Horde_Other', dirname(__FILE__) . '/locale');
-    }
-
-    public function tearDown()
-    {
-        $this->_restoreEnv();
+        parent::setUp();
+        $this->_dict = new Horde_Translation_Handler_Gettext('Horde_Translation', dirname(__FILE__) . '/locale');
+        $this->_otherDict = new Horde_Translation_Handler_Gettext('Horde_Other', dirname(__FILE__) . '/locale');
     }
 
     public function testGettext()
@@ -43,19 +34,4 @@ class Horde_Translation_GettextTest extends PHPUnit_Framework_TestCase
         $this->assertEquals('1 Woche', sprintf($this->_dict->ngettext('%d week', '%d weeks', 1), 1));
         $this->assertEquals('2 Wochen', sprintf($this->_dict->ngettext('%d week', '%d weeks', 2), 2));
     }
-
-    private function _setEnv($value)
-    {
-        foreach (array('LC_ALL', 'LANG', 'LANGUAGE') as $env) {
-            $this->_env[$env] = getenv($env);
-            putenv($env . '=' . $value);
-        }
-    }
-
-    private function _restoreEnv()
-    {
-        foreach (array('LC_ALL', 'LANG', 'LANGUAGE') as $env) {
-            putenv($env . '=' . $this->_env[$env]);
-        }
-    }
 }
diff --git a/framework/Translation/test/Horde/Translation/TestBase.php b/framework/Translation/test/Horde/Translation/TestBase.php
new file mode 100644 (file)
index 0000000..de61d44
--- /dev/null
@@ -0,0 +1,42 @@
+<?php
+/**
+ * @author     Jan Schneider <jan@horde.org>
+ * @license    http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @category   Horde
+ * @package    Translation
+ * @subpackage UnitTests
+ */
+class Horde_Translation_TestBase extends PHPUnit_Framework_TestCase
+{
+    private $_env;
+
+    public function setUp()
+    {
+        try {
+            $this->setLocale(LC_ALL, 'de_DE.UTF-8');
+        } catch (PHPUnit_Framework_Exception $e) {
+            $this->markTestSkipped('Setting the locale failed. de_DE.UTF-8 might not be supported.');
+        }
+        $this->_setEnv('de_DE.UTF-8');
+    }
+
+    public function tearDown()
+    {
+        $this->_restoreEnv();
+    }
+
+    private function _setEnv($value)
+    {
+        foreach (array('LC_ALL', 'LANG', 'LANGUAGE') as $env) {
+            $this->_env[$env] = getenv($env);
+            putenv($env . '=' . $value);
+        }
+    }
+
+    private function _restoreEnv()
+    {
+        foreach (array('LC_ALL', 'LANG', 'LANGUAGE') as $env) {
+            putenv($env . '=' . $this->_env[$env]);
+        }
+    }
+}
diff --git a/framework/Translation/test/Horde/Translation/WrapperTest.php b/framework/Translation/test/Horde/Translation/WrapperTest.php
new file mode 100644 (file)
index 0000000..53402e6
--- /dev/null
@@ -0,0 +1,37 @@
+<?php
+
+require_once dirname(__FILE__) . '/TestBase.php';
+
+/**
+ * @author     Jan Schneider <jan@horde.org>
+ * @license    http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @category   Horde
+ * @package    Translation
+ * @subpackage UnitTests
+ */
+class Horde_Translation_WrapperTest extends Horde_Translation_TestBase
+{
+    public function testWrappers()
+    {
+        $this->assertEquals('Heute', Horde_Translation_TestWrapper::t('Today'));
+        $this->assertEquals('1 Woche', sprintf(Horde_Translation_TestWrapper::ngettext('%d week', '%d weeks', 1), 1));
+    }
+}
+
+class Horde_Translation_TestWrapper extends Horde_Translation
+{
+    /**
+     * Returns the translation of a message.
+     *
+     * @var string $message  The string to translate.
+     *
+     * @return string  The string translation, or the original string if no
+     *                 translation exists.
+     */
+    static public function t($message)
+    {
+        self::$_domain = 'Horde_Translation';
+        self::$_directory = 'locale';
+        return parent::t($message);
+    }
+}