Pull to refresh

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

PHP *
Учитывая наличие интереса к этой теме у сообщества, продолжаю знакомить со своими плагинами для 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';


Не хочется раздувать статью до неприличных размеров, поэтому пока остановлюсь. Продолжение следует.
Tags:
Hubs:
Total votes 11: ↑9 and ↓2 +7
Views 4.8K
Comments Comments 13