ZF-12547: Gettext adapter cannot translate plurals when the target language has only one plural form

Description

When a target language only has one plural form, calls to {{Zend_Translate::plural()}} just return the first character of the string.

Consider these two translation files (French - 2 plural forms, Turkish - 1 plural form). Compile them with the command "msgfmt XX.po -o XX.mo"


msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"

msgid "There is %d fish"
msgid_plural "There are %d fishes"
msgstr[0] "Il ya %d poisson"
msgstr[1] "Il ya %d poissons"

msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Plural-Forms: nplurals=1; plural=0;\n"

msgid "There is %d fish"
msgid_plural "There are %d fishes"
msgstr[0] "%d balıklar var"

Here is a test script


require 'Zend/Translate.php';

// A language with more than one plural form - works OK
$translate = new Zend_Translate('gettext', 'fr.mo', 'fr');
for ($i=0; $i<5; ++$i) {
    echo $translate->plural('There is %d fish', 'There are %d fishes', $i), PHP_EOL;
}

// A language with only one plural form - does not work
$translate = new Zend_Translate('gettext', 'tr.mo', 'tr');
for ($i=0; $i<5; ++$i) {
    echo $translate->plural('There is %d fish', 'There are %d fishes', $i), PHP_EOL;
}

The actual output is


Il ya %d poisson
Il ya %d poisson
Il ya %d poissons
Il ya %d poissons
Il ya %d poissons
%
%
%
%
%

Note that the turkish translations contain just the first character of the sring.

This comes from code in {{Zend_Translate_Adapter::plural()}} which assumes that plural translations are always arrays. The [0] operator is finding the first character of a string, not the first element of an array.


            $rule = Zend_Translate_Plural::getPlural($number, $locale);
            if (isset($this->_translate[$locale][$plural[0]][$rule])) {
                $this->_routed = array();
                return $this->_translate[$locale][$plural[0]][$rule];
            }

As far as I can tell, the bug comes from Zend_Translate_Adapter_Gettext, and can be fixed by the following patch


Index: Gettext.php
===================================================================
--- Gettext.php (revision 25275)
+++ Gettext.php (working copy)
@@ -122,7 +122,7 @@
                 fseek($this->_file, $transtemp[$count * 2 + 2]);
                 $translate = fread($this->_file, $transtemp[$count * 2 + 1]);
                 $translate = explode("\0", $translate);
-                if ((count($original) > 1) && (count($translate) > 1)) {
+                if (count($original) > 1) {
                     $this->_data[$locale][$original[0]] = $translate;
                     array_shift($original);
                     foreach ($original as $orig) {

An explanation for the patch is that a translation is defined as a plural if there are more than one ENGLISH forms. It does not matter whether there is only one TRANSLATED form.

With the patch, the test script outputs the expected values:


Il ya %d poisson
Il ya %d poisson
Il ya %d poissons
Il ya %d poissons
Il ya %d poissons
%d balıklar var
%d balıklar var
%d balıklar var
%d balıklar var
%d balıklar var

Comments

This issue has been closed on Jira and moved to GitHub for issue tracking. To continue following the resolution of this issues, please visit: https://github.com/zendframework/zf1/issues/66