Сниппет Declension для склонения слов
        Предлагаю вашему вниманию небольшой сниппет для вывода склонения. Работает как фильтр вывода, использовать нужно примерно так:

Как видите, он применяется к любым тегам с числами, а в options нужно указать три формы слова (1 яблоко, 2 яблока и 10 яблок) для русского, или 2 (1 ticket, 2 tickets) для английского.
Для экспериментов можно повызывать сниппет с произвольными числами:
Как вы уже догадались, сниппет был написан для оформления баланса на хостинге, но я подумал, что вам он тоже пригодится.
Если кто-то оформит его в готовый пакет и выложит в репозиторий — не возражаю. Уже давно есть.    
    
    
                                                                                
            [[+balls]] [[+balls:declension=`балл,балла,баллов`]]
Как видите, он применяется к любым тегам с числами, а в options нужно указать три формы слова (1 яблоко, 2 яблока и 10 яблок) для русского, или 2 (1 ticket, 2 tickets) для английского.
Для экспериментов можно повызывать сниппет с произвольными числами:
15 [[*id:input=`15`:declension=`яблоко,яблока,яблок`]]Полный код под катом.<?php
/**
 * Declension of words
 * This algorithm taken from https://github.com/livestreet/livestreet/blob/eca10c0186c8174b774a2125d8af3760e1c34825/engine/modules/viewer/plugs/modifier.declension.php
 */
/** @var array $scriptProperties */
$number = $modx->getOption('input', $scriptProperties, 0);
$forms = $modx->getOption('options', $scriptProperties, '');
if (is_string($forms)) {
	if ($forms[0] == '[') {
		$forms = $modx->fromJSON($forms);
	}
	else {
		$forms = explode(',', $forms);
	}
}
if (!is_numeric($number)) {
	return;
}
if (!is_array($forms) || empty($forms)) {
	return 'Вы должны указать формы слов для склонения. Например [[*id:declension=`яблоко,яблока,яблок`]].';
}
if (count($forms) == 3) {
	$mod100 = $number % 100;
	switch ($number % 10) {
		case 1:
			if ($mod100 == 11) {
				$text = $forms[2];
			}
			else {
				$text = $forms[0];
			}
			break;
		case 2:
		case 3:
		case 4:
			if (($mod100 > 10) && ($mod100 < 20)) {
				$text = $forms[2];
			}
			else {
				$text = $forms[1];
			}
			break;
		case 5:
		case 6:
		case 7:
		case 8:
		case 9:
		case 0:
		default:
			$text = $forms[2];
	}
}
elseif (count($forms) == 2) {
	if ($number == 1) {
		$text = $forms[0];
	}
	else {
		$text = $forms[1];
	}
}
else {
	$text = 'Недостаточно форм слов для склонения';
}
return $text;Как вы уже догадались, сниппет был написан для оформления баланса на хостинге, но я подумал, что вам он тоже пригодится.
Комментарии: 30
                Спасибо, забираю.)            
                    
                а он через аякс не обрабатывает {товара, товаров, товар} в чанке корзины? )            
                    
                Столкнулся однажды с такой же проблемой, так что в оф. репозитории похожее дополнение есть)            
                    
                Я искал как declension =)            
                    
                Поправил, теперь по этому слову его можно найти)))            
                    
                Грамотно! От души, друг! Ещё бы осуществить его работу под минишоп2. :)            
                    
                а в чем проблема? он же как фильтр работает            
                    
                Василий, а на сколько оправдано так много строк кода? У нас в смарти-плагине всего несколько строчек. Все тоже самое, ниразу не было замечено, чтобы склонения как-то не так были. 
{$count|spell:«яблоко»:«яблока»:«яблок»}
                    {$count|spell:«яблоко»:«яблока»:«яблок»}
                Это адаптация чужого кода, плюс здесь можно указывать 2 формы для английских слов.
Ну и лично я люблю, когда понятно, а не коротко. PHP всё равно оптимизирует исходники при выполнении.
                    Ну и лично я люблю, когда понятно, а не коротко. PHP всё равно оптимизирует исходники при выполнении.
                Ясно. ОК.            
                    
                На JS тоже так можно =)
                    function declineWord(number, titles)  {  
    cases = [2, 0, 1, 1, 1, 2];  
    return titles[ (number%100>4 && number%100<20)? 2 : cases[(number%10<5)?number%10:5] ];  
}declineWord(2,['кнопка','кнопки','кнопок']);//2 кнопки            
                Не уверен, что нужна его реализация в виде отдельного пакета, хотя я бы наверное собрал несколько таких мелочей в один пакет под названием Утилиты. Сюда можно добавить еще форматирование чисел, дат и тд, тогда будет иметь смысл делать пакет. В остальном, из того, что видел, реализация declension занимает 20 строчек кода максимум.            
                    В остальном, из того, что видел, реализация declension занимает 20 строчек кода максимум.Обрати внимание — это код из LiveStreet, ты его, вероятно, не видел.
Можно и в одну строку сжать — не проблема. От этого кому лучше будет?
Я вообще не понимаю экономии на строках. А есть еще люди, которые на скобках экономят, и на пробелах. Должно быть понятно, тем более, когда выкладываешь что-то для других.
                А еще на здоровье экономят :-P            
                    
                Я не к формату придираюсь, и не считаю пробельные строки и отступы, это же понятно. 
Я к тому, что функция нужная, но не такая важная, чтобы из нее пакет делать. Алгоритм элементарный, такие задачки на информатике в школе проходить нужно и пишется он за пару минут. Это сейчас не укор твоим способностям, они неоспоримы.
                    Я к тому, что функция нужная, но не такая важная, чтобы из нее пакет делать. Алгоритм элементарный, такие задачки на информатике в школе проходить нужно и пишется он за пару минут. Это сейчас не укор твоим способностям, они неоспоримы.
                Да про пакет понятно, тем более, что он уже есть.            
                    
                Давно пользовался modx.com/extras/package/numeralstring
Но поскольку для новых версий MODX его из репозитория не скачать, можно использовать обычный сниппет:
                    Но поскольку для новых версий MODX его из репозитория не скачать, можно использовать обычный сниппет:
<?php
/**
 *
 * @package numeralString
 * @author Kirill A. <kirusanov@gmail.com>
 *
 * Числительное по-русски.
 * На выходе число и три варианта написания: 1 - "*уй", 2 - "*уя", 5 - "*уев".
 * Никаких чанков для вывода - просто возвращает один из вариантов числительного.
 *
 * @property count число
 * @property one числительное для 1
 * @property two числительное для 2
 * @property five числительное для 5
 *
 */
$count = !empty($scriptProperties['count']) ? abs((int)$scriptProperties['count']) : 0;
$one = !empty($scriptProperties['one']) ? $scriptProperties['one'] : 'голос';
$two = !empty($scriptProperties['two']) ? $scriptProperties['two'] : 'голоса';
$five = !empty($scriptProperties['five']) ? $scriptProperties['five'] : 'голосов';
$showNumber = !empty($scriptProperties['showNumber']) ? $scriptProperties['showNumber'] : 0;
if ($showNumber == 1) {
if (preg_match('/^1$|\d*[02-9]1$/', $count)) { return $count.' '.$one; }
if (preg_match('/^[2-4]$|\d*[02-9][2-4]$/', $count)) { return $count.' '.$two; }
return $count.' '.$five;
}
else {
if (preg_match('/^1$|\d*[02-9]1$/', $count)) { return $one; }
if (preg_match('/^[2-4]$|\d*[02-9][2-4]$/', $count)) { return $two; }
return $five;
}А дальше вызывать:[[!numeralString? &count=`123` &one=`голос`&two=`голоса`&five=`голосов`]]            
                И всё же, может быть оформить это решение как отдельный пакет для репозитория modstore.pro/ ?
Почему я поднял этот вопрос:
потому что сейчас я решил «как обычно» не заморачиваясь скачать пакет «Units» из офф-репозитория, но его там не оказалось (не знаю, конфликт версий с MODX наверное). Дальше я вспомнил про этот сниппет и решил вбить его здесь на сообществе в поиск. Но подобрать подходящее слово у меня не получилось, и по «Units» тоже эта статья не нашлась. И пришлось мне кликать по пагинации раз 20 пока я не нашел эту статью (в закладках в профиле тоже куча статей и также долго пришлось её искать).
Я понимаю, что решение для кого-то несложное, но зачем каждый раз его велосипедить, если быстрее скачать и использовать?
                    Почему я поднял этот вопрос:
потому что сейчас я решил «как обычно» не заморачиваясь скачать пакет «Units» из офф-репозитория, но его там не оказалось (не знаю, конфликт версий с MODX наверное). Дальше я вспомнил про этот сниппет и решил вбить его здесь на сообществе в поиск. Но подобрать подходящее слово у меня не получилось, и по «Units» тоже эта статья не нашлась. И пришлось мне кликать по пагинации раз 20 пока я не нашел эту статью (в закладках в профиле тоже куча статей и также долго пришлось её искать).
Я понимаю, что решение для кого-то несложное, но зачем каждый раз его велосипедить, если быстрее скачать и использовать?
                Спасибо!            
                    
                На одном форуме народ соревновался в самом «компактном» решении этой задачи ))
Победило такое решение:
                    Победило такое решение:
<?php
if($n!=''){
return= $n%10==1&&$n%100!=11?$w1:($n%10>=2&&$n%10<=4&&($n%100<10||$n%100>=20)?$w2:$w3);
}Ну и вызываем:[[Snippet? &n=`123` &w1=`год` &w2=`года` &w3=`лет` ]]            
                Интересное решение! В закладки!            
                    
                Да, только "=" после return долой, естессно ))):
                    <?php
if($n!=''){
return $n%10==1&&$n%100!=11?$w1:($n%10>=2&&$n%10<=4&&($n%100<10||$n%100>=20)?$w2:$w3);
}            
                А как для корзины minishop2 прикрутить данное решение? Я так понимаю из-за аякса этот код не работает.            
                    
                Подскажите пожалуйста, в документации про Парсер pdoTools есть такой модификатор:
declension (decl) — склоняет слово, следующее за числом по правилам русского языка. Например: 1 яблоко, 2 яблока, 10 яблок.
и пример:
чанк обёртки комментариев содержит переменную {$total} — количество комментариев. Хочу добавить склонение, но оно не хочет работать, хм… вот чанк tpl_commentsWrapper
                    declension (decl) — склоняет слово, следующее за числом по правилам русского языка. Например: 1 яблоко, 2 яблока, 10 яблок.
и пример:
{6 | declension : 'яблоко|яблока|яблок'} // яблок
{3 | declension : 'яблоко|яблока|яблок' : true} // 3 яблока
{101 | decl : 'яблоко,яблока,яблок' : false : ','} // яблокоУ меня для статей сделаны комментарии при помощи компонента Tickets, теперь к сути:чанк обёртки комментариев содержит переменную {$total} — количество комментариев. Хочу добавить склонение, но оно не хочет работать, хм… вот чанк tpl_commentsWrapper
<section class="inner-bottom-xs comments">
    <h3 class="title">(<span id="comment-total">{$total}</span>) {$total | declension:'Комментарий|Комментария|Комментариев'}- </h3>
    <div id="comments-wrapper">
        <div class="comment-list" id="comments">
            {$comments}
        </div>
    </div>
    <div id="comments-tpanel">
        <div id="tpanel-refresh"></div>
        <div id="tpanel-new"></div>
    </div>
</section>Может подскажете что не так делаю, ибо не склоняет переменную. Если подставлять цифры то склоняет, а переменную не хочет.            
                В новых версиях pdoTools общее количество результатов не считается, если не указать это специально, для скорости.
Так что сейчас у тебя нет этой переменной, он пустая, и количество комментариев выставляется через javascript.
Укажи &setTotal=`1` в вызове TicketsComments, и всё должно заработать.
                    Так что сейчас у тебя нет этой переменной, он пустая, и количество комментариев выставляется через javascript.
Укажи &setTotal=`1` в вызове TicketsComments, и всё должно заработать.
                Спасибо. Заработало. А сильно это на скорость влияет?            
                    
                Скорость надо проверять, зависит от многих факторов, но на большом количестве записей подсчёт результатов может украсть полсекунды или больше. 
Да и дело даже не в скорости, а в том, что при добавлении нового комментария их общее количество изменится, а склонение — нет.
Поэтому лучше или оставить как есть, без склонения, или делать его на js — и тогда total вообще не нужен.
                    Да и дело даже не в скорости, а в том, что при добавлении нового комментария их общее количество изменится, а склонение — нет.
Поэтому лучше или оставить как есть, без склонения, или делать его на js — и тогда total вообще не нужен.
                Меня вот что сбивает с толку, переменная total без модификатора выводит количество, а с модификатором не хочет… получается что количество без модификатора считается без настройки 'set total'=>1, а с модификатором надо включать эту настройку… буду знать, спасибо.            
                    
                Еще раз — нет, не выводит она ничего.
Это после загрузки страницы javascript подставляет количество комментов. Открой исходник страницы и увидишь на месте переменной, что там пусто.
                    Это после загрузки страницы javascript подставляет количество комментов. Открой исходник страницы и увидишь на месте переменной, что там пусто.
                            Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
                    
            
                    
                    
                