Всем - привет. Недавно работал на проектом 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 штука
Как видите, функция адекватно отрабатывает как с дробными, так и с отрицательными числами. У многих примеров из сети с этим возникают проблемы.