Простейшая функция склонения слов после числительных

На WordPress-сайтах, как правило, информация о количестве комментариев выглядит текстом вида комментариев: 21. Более красиво это выглядело бы так: 21 комментарий.

WordPress, естественно, не учитывает особенности русского языка, когда окончание слова после числа меняется в зависимости от этого числа.

Я предлагаю вашему вниманию простейшую PHP-функцию, которая решает данную задачу. Покажу 2 варианта этой функции.

Вариант 1

Когда нужен текст вида 21 комментарий.

В файле functions.php темы вставляем функцию:

function plural_form($number, $after) {
	$cases = array (2, 0, 1, 1, 1, 2);
	echo $number.' '.$after[ ($number%100>4 && $number%100<20)? 2: $cases[min($number%10, 5)] ];
}

А в то место, где нужно выводить текст о количестве комментов, вставляем такой код:

<?php
plural_form(
	get_comments_number(),
	/* варианты написания для количества 1, 2 и 5 */
	array('комментарий','комментария','комментариев')
);
?>

Вариант 2

Когда нужен текст вида опубликован 21 комментарий. Т.е. в данном случае склоняется слово и перед числом, и после числа.

В файле functions.php темы вставляем функцию:

function plural_form($number,$before,$after) {
	$cases = array(2,0,1,1,1,2);
	echo $before[($number%100>4 && $number%100<20)? 2: $cases[min($number%10, 5)]].' '.$number.' '.$after[($number%100>4 && $number%100<20)? 2: $cases[min($number%10, 5)]];
}

А в то место, где нужно выводить текст о количестве комментов, вставляем такой код:

<?php
plural_form(
	get_comments_number(),
	/* варианты написания для количества 1, 2 и 5 */
	array('опубликован','опубликовано','опубликовано'),
	array('комментарий','комментария','комментариев')
);
?>

Если нужно, чтобы текст был ссылкой, тогда делаем так:

<a href="<?php the_permalink() ?>#comments">[тут вставляем вышеуказанный PHP-код, который выводит количество комментов]</a>

Вот, собственно, и все.

Комментарии (19)

  1. Евгений
    4 ноября 2013 г. в 13:07

    Спасибо за функцию.
    Но возник вопрос, как быть если при отсутствии комментариев выводилось не “0 комментариев”, а “Нет комментариев”?

    1. 4 ноября 2013 г. в 14:02 / ответ на коммент Евгений

      Вот такой вариант придумал:

      <?php
      if (get_comments_number() == 0) {
      	echo 'Нет комментариев';
      } else {
      	plural_form(
      		get_comments_number(),
      		/* варианты написания для количества 1, 2 и 5 */
      		array('комментарий','комментария','комментариев')
      	);
      }
      ?>
      
      1. Евгений
        4 ноября 2013 г. в 19:23 / ответ на коммент Dimox

        Благодарю!

  2. Павел
    11 мая 2015 г. в 08:21

    Здравствуйте! Подскажите пожалуйста, как склонить выражение:
    — если одна рубрика, то «Опубликовано в рубрике»;
    — если рубрик несколько, то «Опубликовано в рубриках».

    Буду признателен за помощь.

    1. Vadim
      21 мая 2015 г. в 18:07 / ответ на коммент Павел
      switch($number) {
      	case 1:
      		echo "Опубликовано в рубрике";
      		break; 
      	default:
      	echo "Опубликовано в рубриках";
      }
      
      1. Павел
        25 мая 2015 г. в 23:04 / ответ на коммент Vadim

        Вадим, спасибо!
        Но, как сюда теперь прикрутить WordPress-функцию ?

  3. Александр
    11 января 2016 г. в 08:12

    Что то вы тут велосипеды придумываете.
    Начну с этого:

    switch($number) {
      case 1:
        echo "Опубликовано в рубрике";
        break; 
      default:
      echo "Опубликовано в рубриках";
    }
    

    Тут достаточно простого условия:

    echo ($number ? 'Опубликовано в рубриках' :'Опубликовано в рубрике');

    Незачем строить конструкции из свитчей без надобности.
    Теперь перейдем к самой функции склонения.
    Вот тут: (Извиняюсь конечно)

    function plural_form($number,$before,$after) {
      $cases = array(2,0,1,1,1,2);
      echo $before[($number%100>4 &amp;&amp; $number%100<20)? 2: $cases[min($number%10, 5)]].' '.$number.' '.$after[($number%100>4 &amp;&amp; $number%100<20)? 2: $cases[min($number%10, 5)]];
    }

    Но это бред сивой кобылы.
    Достаточно просто переписать нормально функцию например вот так:
    Это функция моя просто название поставил ваше.

    function plural_form($n, $w, $t = false){
        $c = array(2, 0, 1, 1, 1, 2);
        return (!$t ? $n.' ' : '').$t[ ($n % 100 > 4 &amp;&amp; $n % 100 < 20) ? 2 : $c[min($n % 10, 5)] ];
    }
    

    А теперь вывод:

    echo plural_form($count,array('опубликован','опубликовано','опубликовано'),1).' '.plural_form($count, array('комментарий','комментария','комментариев'));
    

    Тем самым немного изменив функцию мы убиваем сразу несколько зайцев.
    1. Нам больше не надо изменять функцию. Так как она подойдет для всего.
    2. Мы расширили функционал сайта. И немного уменьшили нагрузку.(Хотя для Wp давно забило о наблюдении за нагрузкой)

    1. Евгений
      25 июня 2016 г. в 14:23 / ответ на коммент Александр

      Добрый день. А как все это можно преобразовать в вордпресовский шорткод?

      У меня есть шорткод, который выводит количество записей в категории:

      /* Шорткод кол-ва записей */
      function kol_zap($atts) {
      extract(shortcode_atts(array(
      "id" => ''
      ), $atts));
      $post_count = get_category($id)->category_count;
      $cat_name = get_category($id)->name;
      $cat_slug = get_category($id)->slug;
      return ''.$post_count.'';
      }
      add_shortcode('kolvo', 'kol_zap');
      

      Хотелось, чтобы этот шорткод выводил после числа – слово запись(‘и’, ‘ей’).

      Заранее спасибо.

  4. Виталий Анохин
    13 января 2017 г. в 14:03

    Доработал вашу функцию =)
    Теперь есть все проверки, проще задать текст в переменной и можно его отключать.

    <?php
    
    function plural_form($number,$before,$after,$ifzero) {
      if ($number == 0) {echo $ifzero;} else {
        $cases = array(2,0,1,1,1,2);
        if ($before <> 0) {echo $before[($number%100>4 &amp;&amp; $number%100<20)? 2: $cases[min($number%10, 5)]].' ';}
        echo $number;
        if ($after <> 0) {echo ' '.$after[($number%100>4 &amp;&amp; $number%100<20)? 2: $cases[min($number%10, 5)]];}
      }
    }
    
    $anynumber = 55; // число которое надо описать
    $anytextformbefore = array('продан','продано','продано');
    //если указать значение 0 вместо массива, то текст не выводится
    $anytextformafter = array('билет','билета','билетов');
    $anytextformifzero = "билетов нет";
    
    plural_form($anynumber, $anytextformbefore,  $anytextformafter, $anytextformifzero);
    
    ?>
    
  5. Виталий Анохин
    13 января 2017 г. в 14:30

    А если надо записать текст в переменную, что будет правильно, то код будет такой

    <?php
    	function plural_form($number,$before,$after,$ifzero) {
    		if ($number == 0) {return $ifzero;} else {
    			$retval = "";
    			$cases = array(2,0,1,1,1,2);
    			if ($before <> 0) {$retval .= $before[($number%100>4 &amp;&amp; $number%100<20)? 2: $cases[min($number%10, 5)]].' ';}
    			$retval .= $number;
    			if ($after <> 0) {$retval .= ' '.$after[($number%100>4 &amp;&amp; $number%100<20)? 2: $cases[min($number%10, 5)]];}
    			return $retval;
    		}
    	}
    
    	$anynumber = 55; // число которое надо описать
    	$anytextformbefore = array('продан','продано','продано');
    	//если указать значение 0 вместо массива, то текст не выводится
    	$anytextformafter = array('билет','билета','билетов');
    	$anytextformifzero = "билетов нет";
    	// результат в переменной
    	$strtext = plural_form($anynumber, $anytextformbefore,  $anytextformafter, $anytextformifzero);
    	echo $strtext;
    ?>
    
  6. Иван
    10 марта 2017 г. в 00:47

    Здавствуйте! Использовал вашу функцию, был доволен, но столкнулся с такой проблемой. При поиске нашлось 15 материалов и выдало такую ошибку:
    По Вашему запросу
    Notice (8): Undefined offset: 2 [APP\View\Helper\SearchingHelper.php, line 10] 15 ответов :

    вызываю так

    echo plural_form(count($search_res), ['найден', 'найдено'], ['ответ', 'ответа', 'ответов'])
    

    а код функции как в этой статье – Вариант 2
    Подскажите как решить эту проблемку.

  7. Антон
    23 января 2018 г. в 06:35

    Здравствуйте, а как использовать для склонения поисковых запросов? Пример: Найдено (найден) NN поисковых запроса, запросов или запрос.
    Код из двух вариантов отображения ниже:

    <?php echo $count ?> <?php echo _n('поисковый запрос', 'поисковых запроса', $count, 'blockster-wp') ?>
    1. 23 января 2018 г. в 08:47 / ответ на коммент Антон

      Используйте второй вариант и вместо get_comments_number() вставьте $count.

  8. Антон
    24 января 2018 г. в 17:58

    Благодарю, так намного лучше, вот только как учесть нормы склонения двух языков, когда для сайта используется английский и русский? Ведь текст перевода внесен в файл .PO. Или никак.

    1. 24 января 2018 г. в 18:21 / ответ на коммент Антон

      Вот это не знаю.

  9. Олег
    15 февраля 2018 г. в 18:58

    Спасибо за функцию. Оказалась очень полезна.
    Но я ее немного доработал.
    Может кому пригодится.

    Сами функции:

    <?php
    	function get_decline($value,$string) {
    		$cases = array(2,0,1,1,1,2);
    		return $string[($value%100>4 &amp;&amp; $value%100<20)? 2: $cases[min($value%10, 5)]];
    	}
    	
    	function get_decline_string($prefix,$value,$suffix, $in_array = false) {
    		$cases = array(2,0,1,1,1,2);
    		$prefix_value = $prefix;
    		if(is_array($prefix)){
    			$prefix_value = get_decline($value,$prefix);
    		}
    		$suffix_value = $suffix;
    		if(is_array($suffix)){
    			$suffix_value = get_decline($value,$suffix);
    		}
    		if($in_array == true){
    			return array(
    				'prefix' => $prefix_value,
    				'value' => $value,
    				'suffix' => $suffix_value
    			);
    		} else {
    			return $prefix_value.$value.$suffix_value;
    		}
    	}
    ?>
    

    Варианты использования

    <?php
    	/* количество комментариев */
    	$comments = 5;
    	
    	/* вариант 1 */
    	$var1 = get_decline_string(
    		/* варианты написания префикса для количества 1, 2 и 5 */
    		array('опубликован ','опубликовано ','опубликовано '),
    		/* число */
    		$comments,
    		/* варианты написания суффикса для количества 1, 2 и 5 */
    		array(' комментарий',' комментария',' комментариев')
    	);
    	
    	/* вариант 2 */
    	$var2 = get_decline_string(
    		/* префикс */
    		'опубликовано: ',
    		/* число */
    		$comments,
    		/* варианты написания суффикса для количества 1, 2 и 5 */
    		array(' комментарий',' комментария',' комментариев')
    	);
    	
    	/* вариант 3 */
    	$var3 = get_decline_string(
    		/* варианты написания префикса для количества 1, 2 и 5 */
    		array('опубликован: ','опубликовано: ','опубликовано: '),
    		/* число */
    		$comments,
    		/* суффикс */
    		' комм.'
    	);
    	
    	/* вариант 4 */
    	$var4 = get_decline_string(
    		/* префикс */
    		null,
    		/* число */
    		$comments,
    		/* суффикс */
    		array(' комментарий',' комментария',' комментариев')
    	);
    	
    	/* вариант 5 */
    	$var5 = get_decline_string(
    		/* варианты написания префикса для количества 1, 2 и 5 */
    		array('опубликован: ','опубликовано: ','опубликовано: '),
    		/* число */
    		$comments,
    		/* суффикс */
    		null
    	);
    	
    	/* вариант 6 */
    	$var6 = get_decline(
    		/* число */
    		$comments,
    		/* суффикс */
    		array('комментарий','комментария','комментариев')
    	);
    	
    	/* вариант 7 */
    	$var7 = get_decline_string(
    		/* варианты написания префикса для количества 1, 2 и 5 */
    		array('опубликован ','опубликовано ','опубликовано '),
    		/* число */
    		$comments,
    		/* варианты написания суффикса для количества 1, 2 и 5 */
    		array(' комментарий',' комментария',' комментариев'),
    		/* вывести как массив */
    		true
    	);
    ?>
    

    Вывод:

    <?php
    	echo $var1 . '<br /&amp;gt';
    	echo $var2 . '<br /&amp;gt';
    	echo $var3 . '<br /&amp;gt';
    	echo $var4 . '<br /&amp;gt';
    	echo $var5 . '<br /&amp;gt';
    	echo $var6 . '<br /&amp;gt';
    	echo '<pre>' . print_r($var7, true) . '</pre>';
    ?>
    

    Результат:

    опубликовано 5 комментариев<br />
    опубликовано: 5 комментариев<br />
    опубликовано: 5 комм.<br />
    5 комментариев<br />
    опубликовано: 5<br />
    комментариев<br />
    
    Array
    	(
    		[prefix] => опубликовано 
    		[value] => 5
    		[suffix] =>  комментариев
    	)
    

    Спасибо за внимание.

    1. Антон
      15 февраля 2018 г. в 19:17 / ответ на коммент Олег

      А для чего это может пригодиться? Poedit не достаточно?

  10. 27 мая 2018 г. в 11:22

    Вот спасибочки. Это мне точно пригодится.

  11. 1 февраля 2019 г. в 08:56

    Огромное спасибо! Очень помогло! Люблю компактные решения :)

Ваш комментарий

Жирный текст

Ссылка

Цитата

Внутристрочный код

CSS-код

HTML-код

JavaScript-код

PHP-код