Odmiana słowiańskich rzeczowników według liczb

Opublikowano: [Źródło]
Tagi:  i18n php symfony

Odmiana rzeczowników w językach słowiańskich jest trochę bardziej skomplikowana niż w językach zachodnich. Z pierwszą próbą zetknąłem się dostosowując swój pierwszy moduł backendowy. Szukając sposobu przetłumaczenia nie tylko tekstów, ale i odmiany ich, natknąłem się na post: Plural forms and format_number_choice na forum symfony.

Znajdująca się tam formuła dla helpera format_number_choice() miała kilka wad, dlatego na podstawie istniejącej zaproponowałem własną, która radzi sobie ze wszystkimi wariacji liczb:

'[0] brak|[1] 1 wynik|{n: n % 10 > 1 && n % 10 < 5 && ( n < 11 || n > 14 ) && ( n % 100 < 11 || n % 100 > 14 ) } %1% wyniki|[5,+Inf] %1% wyników '

Idąc dalej, stworzyłem funkcję biblioteczną, która przyjmuje w parametrach liczbę, oraz zestaw odmian rzeczownika, wybierając odpowiednią jego formę do liczby:

class Fizyk
{
    /**
     * Function that returns proper inflection based on a number that describes it's quantity for slavic languages.

     * There are four forms: none, one singular and two plurar.
     * $word array indexes 1, 2 and 3 are mandatory, while 0 is optional
     * @param array $words
     * @param integer $number
     * @return string
     * @author Grzegorz Śliwiński
     */
    static public function slavicWordFormNumberChoice( Array $words, $number)
    {
        //throw exception if passed array doesn't kontain 1st, 2nd or 3rd form
        if( !array_key_exists( 1, $words) || !array_key_exists( 2, $words) || !array_key_exists( 3, $words ) )
        {
            //listing all keys
            $keys = '';
            foreach( array_keys( $words ) as $value )
            {
                $keys .= $value.' ';
            }
            //throwning exception
            throw new sfException( sprintf('Word array is incomplete! Should contain indexes 1, 2 and 3. Your contains: %s', $keys ) );
        }

        //take care of the none case with word set
        if( $number == 0 && array_key_exists(0, $words) )
        {
            return $words[0];
        }
        //take care of the none case without word set
        elseif( $number == 0 && !array_key_exists(0, $words) )
        {
            $wordIndex = 3;
        }
        //One is always the same
        elseif( $number == 1 )
        {
            $wordIndex = 1;
        }
        //Second case: numbers from x2 to x4 without those from x12 to x14 (x - any number)
        elseif( $number % 10 > 1 && $number % 10 < 5 && ( $number < 11 || $number > 14 )
                && ( $number % 100 < 11 || $number % 100 > 14 ) )
        {
            $wordIndex = 2;
        }
        else
        {
            $wordIndex = 3;
        }
        //we return numbered phrase to the world
        return $number.' '.$words[$wordIndex];
    }
}

Jedynym mankamentem tej metody jest konieczność zdefiniowania kluczy tablicy przekazywanych słów, ale akceptuje zestaw słów wszelakich.

Comments powered by Disqus