JS склонение слов в зависимости от рядом стоящего числа

Всем - привет. Недавно работал на проектом smart-screener.com и там часто приходилось приводить в порядок склонение существительных. Например, в зависимости от числа, нужно было правильно подставить слова (месяц, месяца, месяцев) или (фонд, фонда, фондов) и так далее.

Думаю, все, кто занимается разработкой рано или поздно сталкиваются с такой задачей, поэтому решил сделать заметку об этом в блоге. Огромное количество людей говорят, что используют сайт как справочник, поэтому такой пост точно будет не лишним.

Кроме того, мне не нравилось, как во многих примерах в сети отрабатывало склонение при дробных значениях. Например, в случае 12.21 я получал окончание "рублей", вместо "рубля". Мне же нужно - двенадцать целых двадцать одна сотая "рубля". Поэтому пришел к такому решению:

  normalize_count_form = (number, words_arr) => {
    number = Math.abs(number);
    if (Number.isInteger(number)) {
      let options = [2, 0, 1, 1, 1, 2];
      return words_arr[(number % 100 > 4 && number % 100 < 20) ? 2 : options[(number % 10 < 5) ? number % 10 : 5]];
    }
    return words_arr[1];
  }

Как использовать функцию?

Для того, чтобы применить функцию, нужно передать в качестве первого аргумента число или переменную, содержащую число, а в качестве второго аргумента - массив или переменную содержащую массив с правильными формами слов в зависимости от числа. Звучит немного запутанно, но на самом деле - все просто. Примеры использования:

normalize_count_form(12.21, ['рубль', 'рубля', 'рублей']);
normalize_count_form(7, ['арбуз', 'арбуза', 'арбузов']);
normalize_count_form(1.5, ['яблоко', 'яблока', 'яблок']);
normalize_count_form(100, ['гривна', 'гривны', 'гривен']);
normalize_count_form(-121, ['штука', 'штуки', 'штук']);

Результат:

// 12.21 рубля
// 7 арбузов
// 1.5 яблока
// 100 гривен
// -121 штука

Как видите, функция адекватно отрабатывает как с дробными, так и с отрицательными числами. У многих примеров из сети с этим возникают проблемы.

Добавить комментарий