Просмотр исходного кода

[GENERIC] Zend_Translate:

- added a way to define custom plural rules

git-svn-id: http://framework.zend.com/svn/framework/standard/trunk@19669 44c647ce-9c0f-0410-b52a-842ac1e357ba
thomas 16 лет назад
Родитель
Сommit
0d9edb171a

+ 70 - 0
documentation/manual/en/module_specs/Zend_Translate-Plurals.xml

@@ -290,6 +290,76 @@ array(
 
     </sect2>
 
+    <sect2 id="zend.translate.plurals.customrules">
+        <title>Custom plural rules</title>
+
+        <para>
+            In rare cases it could be useful to be able to define own plural rules. See chinese for
+            example. This language defines two plural rules. Per default it does not use plurals.
+            But in rare cases it uses a rule like <emphasis>(number == 1) ? 0 : 1</emphasis>.
+        </para>
+
+        <para>
+            Also when you want to use a language which has no known plural rules, and would want to
+            define your own rules.
+        </para>
+
+        <para>
+            This can be done by using <methodname>Zend_Translate_Plural::setRule()</methodname>.
+            The method expects two parameters which must be given. A rule, which is simply a
+            callback to a self defined method. And a locale for which the rule will be used.
+        </para>
+
+        <para>
+            Your rule could look like this:
+        </para>
+
+        <programlisting language="php"><![CDATA[
+public function MyRule($number) {
+    return ($number == 10) ? 0 : 1;
+}
+]]></programlisting>
+
+        <para>
+            As you see, your rule must accept one parameter. It is the number which you will use to
+            return which plural the translation has to use. In our example we defined that when we
+            get a '10' the plural definition 0 has to be used, in all other cases we're using 1.
+        </para>
+
+        <para>
+            Your rules can be as simple or as complicated as you want. You must only return an
+            integer value. The plural definition 0 stands for singular translation, and 1 stands for
+            the first plural rule.
+        </para>
+
+        <para>
+            To activate your rule, and to link it to the wished locale, you have to call it like
+            this:
+        </para>
+
+        <programlisting language="php"><![CDATA[
+Zend_Translate_Plural::setPlural('MyPlural', 'zh');
+]]></programlisting>
+
+        <para>
+            Now we linked our plural definition to the chinese language.
+        </para>
+
+        <para>
+            You can define one plural rule for every language. But you should be aware that you set
+            the plural rules before you are doing translations.
+        </para>
+
+        <note>
+            <title>Define custom plurals only when needed</title>
+
+            <para>
+                <classname>Zend_Translate</classname> defines plurals for most known languages.
+                You should not define own plurals when you are not in need. The default rules work
+                most of time.
+            </para>
+        </note>
+    </sect2>
 </sect1>
 <!--
 vim:se ts=4 sw=4 et:

+ 48 - 1
library/Zend/Translate/Plural.php

@@ -30,7 +30,18 @@
 class Zend_Translate_Plural
 {
     /**
+     * Manual rule to use
+     *
+     * @var string
+     */
+    protected static $_plural = array();
+
+    /**
      * Returns the plural definition to use
+     *
+     * @param  integer $number Number for plural selection
+     * @param  string  $locale Locale to use
+     * @return integer Plural number to use
      */
     public static function getPlural($number, $locale)
     {
@@ -43,6 +54,16 @@ class Zend_Translate_Plural
             $locale = substr($locale, 0, -strlen(strrchr($locale, '_')));
         }
 
+        if (isset(self::$_plural[$locale])) {
+            $return = call_user_func(self::$_plural[$locale], $number);
+
+            if (!is_int($return) || ($return < 0)) {
+                $return = 0;
+            }
+
+            return $return;
+        }
+
         switch($locale) {
             case 'bo':
             case 'dz':
@@ -57,6 +78,7 @@ class Zend_Translate_Plural
             case 'th':
             case 'tr':
             case 'vi':
+            case 'zh':
                 return 0;
                 break;
 
@@ -110,7 +132,6 @@ class Zend_Translate_Plural
             case 'te':
             case 'tk':
             case 'ur':
-            case 'zh':
             case 'zu':
                 return ($number == 1) ? 0 : 1;
 
@@ -174,4 +195,30 @@ class Zend_Translate_Plural
                 return 0;
         }
     }
+
+    /**
+     * Set's a new plural rule
+     *
+     * @param string $rule   Callback which acts as rule
+     * @param string $locale Locale which is used for this callback
+     * @return null
+     */
+    public static function setPlural($rule, $locale)
+    {
+        if ($locale == "pt_BR") {
+            // temporary set a locale for brasilian
+            $locale = "xbr";
+        }
+
+        if (strlen($locale) > 3) {
+            $locale = substr($locale, 0, -strlen(strrchr($locale, '_')));
+        }
+
+        if (!is_callable($rule)) {
+            require_once 'Zend/Translate/Exception.php';
+            throw new Zend_Translate_Exception('The given rule can not be called');
+        }
+
+        self::$_plural[$locale] = $rule;
+    }
 }

+ 39 - 0
tests/Zend/TranslateTest.php

@@ -28,6 +28,11 @@ require_once dirname(__FILE__) . '/../TestHelper.php';
 require_once 'Zend/Translate.php';
 
 /**
+ * Zend_Translate_Plural
+ */
+require_once 'Zend/Translate/Plural.php';
+
+/**
  * @category   Zend
  * @package    Zend_Translate
  * @subpackage UnitTests
@@ -637,6 +642,30 @@ class Zend_TranslateTest extends PHPUnit_Framework_TestCase
     }
 
     /**
+     * Tests getting plurals from lowered locale
+     */
+    public function testGettingPluralsUsingOwnRule()
+    {
+        $lang = new Zend_Translate(
+            Zend_Translate::AN_ARRAY,
+            array('singular' =>
+                array('plural_0 (en)',
+                    'plural_1 (en)',
+                    'plural_2 (en)',
+                    'plural_3 (en)'),
+                'plural' => ''), 'en'
+        );
+        $lang->addTranslation(array('msg1' => 'Message 1 (ru)'), 'en_US');
+        $lang->setLocale('en_US');
+
+        Zend_Translate_Plural::setPlural(array($this, 'customPlural'), 'en_US');
+        $this->assertEquals('plural_1 (en)', $lang->translate(array('singular', 'plural', 1)));
+        $this->assertEquals('plural_1 (en)', $lang->plural('singular', 'plural', 1));
+        $this->assertEquals('plural_1 (en)', $lang->translate(array('singular', 'plural', 0)));
+        $this->assertEquals('plural_1 (en)', $lang->plural('singular', 'plural', 0));
+    }
+
+    /**
      * Ignores a raised PHP error when in effect, but throws a flag to indicate an error occurred
      *
      * @param  integer $errno
@@ -650,6 +679,16 @@ class Zend_TranslateTest extends PHPUnit_Framework_TestCase
     {
         $this->_errorOccured = true;
     }
+
+    /**
+     * Custom callback for testGettingPluralsUsingOwnRule
+     *
+     * @param  integer $number
+     * @return integer
+     */
+    public function customPlural($number) {
+        return 1;
+    }
 }
 
 // Call Zend_TranslateTest::main() if this source file is executed directly.