Мои плагины для Smarty. Часть 2

    Учитывая наличие интереса к этой теме у сообщества, продолжаю знакомить со своими плагинами для Smarty. С первой частью можно ознакомиться здесь.


    1.2. Склонение слов

    Насущная проблема: вывести пользователю, сколько комментариев к записи в блоге есть. Самый жуткий вариант: «2 комментариев». Чуть менее ужасный — «Комментариев: 2». Но ведь так хочется увидеть надписи на нормальном русском языке: «1 комментарий», «22 комментария», «38 комментариев»!

    Именно этой цели и служит очередной модификатор declension (с англ. — склонение).

    Формат: {$count|declension:'словоформы':'язык'}, где:
    $count — количество пересчитываемых элементов (не выводится)
    'словоформы' — перечисление через точку с запятой требуемых словоформ для текущего языка. Т.е. для русского это 'пень; пня; пней' (формы для 1, 2 и 5 предметов), для английского — 'stump,stumps' (формы для 1 и нескольких предметов). Допускается (а в моих проектах это основная возможность) задания термина из локализации, в виде: 'группа/термин'.
    'язык' — двухбуквенный код языка, если очень приспичит. Необязателен.

    Примеры использования:
    {$messages} {$messages|declension:'сообщение; сообщения; сообщений'}
    или
    {$messages} {$messages|declension:'Forum/messages'} — когда требуется многоязычность

    Файл smarty/plugins/modifier.declension.php (скачать)
    <?php
    /**
     * Smarty plugin - declension modifier
     * @package Smarty
     * @subpackage plugins
     */

    /**
     * Модификатор declension: склонение существительных по правилам английского языка
     *
     * @param array $forms (напр: 0 => article, 1 => articles)
     * @param int $count
     * @return string
     */
    function smarty_modifier_declension_en($forms$count)
    {
        if (
    $count==1)
            return 
    $forms[0];
        else
            return 
    $forms[1];
    }

    /**
     * Модификатор declension: склонение существительных по правилам русского языка
     *
     * @param array $forms (напр: 0 => пень, 1 => пня, 2 => пней)
     * @param int $count
     * @return string
     */
    function smarty_modifier_declension_ru($forms$count)
    {
        
    $mod100 $count 100;
        switch (
    $count%10) {
            case 
    1:
                if (
    $mod100 == 11)
                    return 
    $forms[2];
                else
                    return 
    $forms[0];
            case 
    2:
            case 
    3:
            case 
    4:
                if ((
    $mod100 10) && ($mod100 20))
                    return 
    $forms[2];
                else
                    return 
    $forms[1];
            case 
    5:
            case 
    6:
            case 
    7:
            case 
    8:
            case 
    9:
            case 
    0:
                return 
    $forms[2];

        }
    }

    /**
     * Модификатор declension: склонение существительных
     *
     * @param int $count
     * @param string $forms
     * @param string $language
     * @return string
     */
    function smarty_modifier_declension($count$forms$language='')
    {
        global 
    $currentLanguage$Language;
        if (!
    $language)
            
    $language $currentLanguage;

        
    $count abs($count);

        
    // Пытаемся выщемить термин из словаря
        if (preg_match('/^(.*)\/(.*)$/'$forms$termine))
        {
            if (
    $termine[1] && $termine[2])
            {
                
    $forms $Language[$termine[1]][$termine[2]];
            }
        }

        
    // Выделяем отдельные словоформы
        
    $forms explode(';'$forms);

        
    $fn 'smarty_modifier_declension_'.$language;
        if (
    function_exists($fn))
        {
            
    // Есть персональная функция для текущего языка
            
    return $fn($forms$count);
        } else {
            
    // Действуем по образу и подобию английского языка
            
    return smarty_modifier_declension_en($forms$count);
        }
    }
    ?>

    Для корректной работы модификатора помимо уже упоминавшегося в прошлых плагинах словаря терминов текущего языка ($Language), требуется ещё и переменная $currentLanguage, указывающая текущий язык. (Я уже упоминал в предыдущей статье, что наличие этих глобальных переменных — это для статьи, в моих оригинальных исходниках там находятся обращения к функциям фреймворка)

    1.3. Размер файлов

    Ещё одна тривиальная задача: корректно отображать размеры файлов. «384 б», «613,8 Кб», «14,1 Тб». Кто-то ведь должен переводить эти тысячи и миллиарды байт в удобный для пользователя вид. У меня этим занимается модификатор filesize.

    Формат: {$filesize|filesize:'точность'}, где:
    'точность' — необязательное количество знаков после запятой для округления результатов.

    Файл smarty/plugins/modifier.filesize.php (скачать)
    <?php
    /**
     * Smarty plugin - filesize modifier
     * 
     * @author Vasily Melenchuk
     * @package Smarty
     * @subpackage plugins
     */

    /**
     * Модификатор filesize: вывод размеров для файлов
     *
     * @param int/float $size
     * @param int $precision - требуемая точность (знаков после запятой)
     * @return string
     */
    function smarty_modifier_filesize($size$precision=2)
    {
        global 
    $Language;

        if(!
    is_numeric($precision) || !is_numeric($size))
        {
            
    // Что-то явно не так
            
    trigger_error('Modifier filesize: Invalid input params');
            return 
    '';
        }

        
    // Находим подходящую величину
        
    $result '?';
        
    $multiplier 1;
        while (
    $multiplier <= 1099511627776// 1 Тб в байтах. Пока хватит
        
    {
            if (
    $size/$multiplier<1
            {
                break;
            } else {
                
    $result round($size/$multiplier$precision).'&nbsp;'.$Language['global']['filesize_'.$multiplier];
            }

            
    $multiplier *= 1024;
        }
        
        
    // Финальный штрих: разделитель дробной части
        
    $result str_replace('.'$Language['global']['decimal_separator'], $result);

        return 
    $result;
    }
    ?>


    Как и в случае с модификатором date (описанном в первой части статьи), я использую таблицы локализации не только для слов и выражений интерфейса, а ещё и для хранения технической информации (здесь — символ разделителя дробной части для текущего языка).

    Для английского языка переводы выглядят так (для русского они мало чем отличаются, не буду дублировать):
        $Language['global']['decimal_separator'] = '.';
        
    $Language['global']['filesize_1'] = 'b';
        
    $Language['global']['filesize_1024'] = 'Kb';
        
    $Language['global']['filesize_1048576'] = 'Mb';
        
    $Language['global']['filesize_1073741824'] = 'Gb';
        
    $Language['global']['filesize_1099511627776'] = 'Tb';


    Не хочется раздувать статью до неприличных размеров, поэтому пока остановлюсь. Продолжение следует.
    Поделиться публикацией

    Похожие публикации

    Комментарии 13
      0
      полезные плугины
        +2
        Еще можно размер определять более красиво (вычитано в комментариях на php.net):

        $units = array(' B', ' KB', ' MB', ' GB', ' TB');
        for ($i = 0; $size > 1024; $i++) $size /= 1024;
        return round($size, 2).$units[$i];
          +1
          или вот так

          function print_traf($input, $dec=2) {
          $prefix_arr = array(« b», « Kb», « Mb», « Gb», « Tb»);
          $value = round($input, $dec);
          $i=0;
          while ($value>1000) { $value /= 1000; $i++; }
          $return_str = round($value, $dec).$prefix_arr[$i];
          return $return_str;
          }
            0
            Всё-таки лучше делить на 1024 ;)
              0
              1000 или 1024 — это обычно зависит от условий.
              некоторые ISP считают, что 1 Mb = 1000 b, а некоторые 1024.
              вот и в каждом частном случае приходится устанавливать свою константу.
                0
                мальчики, не ссорьтесь:

                public static function GetPrettyBytes($bytes, $precision = 1) {
                static $suffix = array ('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB');
                $index = floor(log($bytes + 1, 1024)); // + 1 to prevent -INF
                return sprintf ("%0.{$precision}f %s", $bytes / pow (1024, $index), $suffix[$index]);
                }
          0
          Возникла необходимость перевести один проект с обычного блочного шаблонизатора на smarty для удобства верстальщика, и возник ряд проблем. Задача проста — вынести полностью весь html и оформление в шаблоны.

          Проект крупный и имеет много типов данных для вывода, например очки игрока, их нужно оформлять красным цветом если они отрицательные, зеленым если положительные и серым если равны нулю. Сейчас это реализует php функция, которая возращает название соответствующего стиля. Эта функция используется так же для оформления и других типов данных.

          Я начал переписывать на смарти конструктор таблиц(списков), чтобы верстальщик сам мог управлять логикой представления, но столкнулся с проблемой, что в smarty не предусмотрено описание пользовательских функций на самом же smarty-языке, т.о. выходит, что повторяющуюся логику оформления(как в случае с цветами) для каждого типа данных описывать каждый раз нужно заново, либо жестко описывать её на PHP, что недопустимо, т.к. лишает верстальщика возможности управлять логикой вывода.

          Сопсно вопрос — как это можно решить? можно как нибудь внедрить в smarty возможность использования описанных на smarty-языке функций?

          P.S. одно решение этой проблемы я нашел, но оно мне совсем не по душе.
            0
            Насколько помню — в smarty можно передавать не только данные, но и объекты.
            Передайте объект и в шаблоне вызывайте его метод.
            +1
            У меня вывод размера файла вот так нарисован =)

            function smarty_modifier_fsize($s) {
            $fn = array(«байт», «Кб», «Мб», «Гб»);
            return round($s/pow(1024, ($a = floor(log($s, 1024)))), 2)." ".$fn[$a];
            }

            проще уже, имхо, некуда… Стоит ли говорить, что языковой массив можно сделать внешним, если уж так хочется?
              0
              Так приятнее. Учту.
              0
              Неплохо. Спасибо.
              Продолжайте, пожалуйста =)
                0
                Все почти работает, но вот когда комментариев от 5 и дальше, все равно пишет «комментария»!!! почему??
                  0
                  даже переставляю местами слова, третья форма в упор не работает! выводит «комментария» и все...(

                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                Самое читаемое