cloud-castle / inflector
Многоязычный инфлектор для PHP 8.1+: множественное/единственное число, преобразования регистра, порядковые числительные, slugify с транслитерацией, склонение по падежам и грамматика нескольких языков. Единственная зависимость — словарь cloud-castle/dictionary.
Requires
- php: >=8.1
- ext-mbstring: *
- cloud-castle/dictionary: ^1.3
Requires (Dev)
- cakephp/utility: ^5.2
- deptrac/deptrac: ^3.0 || ^4.0
- doctrine/inflector: ^2.0
- ergebnis/composer-normalize: ^2.45
- friendsofphp/php-cs-fixer: ^3.75
- icanboogie/inflector: ^2.2
- icanhazstring/composer-unused: ^0.9
- illuminate/support: ^10.0
- infection/infection: ^0.29 || ^0.33
- php-parallel-lint/php-parallel-lint: ^1.4
- phpmd/phpmd: ^2.15
- phpstan/extension-installer: ^1.4
- phpstan/phpstan: ^1.12 || ^2.1
- phpstan/phpstan-deprecation-rules: ^1.2 || ^2.0
- phpstan/phpstan-phpunit: ^1.4 || ^2.0
- phpstan/phpstan-strict-rules: ^1.6 || ^2.0
- phpunit/phpunit: ^10.5 || ^11.5
- psalm/plugin-phpunit: ^0.19 || ^0.20
- rector/rector: ^1.2 || ^2.0
- roave/security-advisories: dev-latest
- squizlabs/php_codesniffer: ^3.12 || ^4.0
- symfony/string: ^6.4 || ^7.0
- vimeo/psalm: ^6.0
- webmozart/assert: ^1.11
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-09-08 10:11:02 UTC
README
🇷🇺 Русский · 🇬🇧 English · 🇩🇪 Deutsch · 🇫🇷 Français · 🇪🇸 Español · 🇮🇹 Italiano
CloudCastle Inflector
Многоязычный морфологический инфлектор для PHP 8.1+ с единственной зависимостью — словарём выверенных словоформ
cloud-castle/dictionary. Работает с восемью языками (русский, английский, немецкий, французский, испанский, польский, болгарский, румынский): образование множественного/единственного числа, склонение по 6 падежам, спряжение глаголов, согласование с числительными, определение рода и языка, склонение имён и фамилий, числа прописью и обратно (целые и дроби) и обратимая транслитерация латиница↔кириллица.
Установка
composer require cloud-castle/inflector
Требуется PHP 8.1+.
Быстрый старт
<?php
use CloudCastle\Inflector\Inflector;
use CloudCastle\Inflector\Language;
use CloudCastle\Inflector\GrammaticalCase;
$en = new Inflector(Language::English);
echo $en->pluralize('category'); // «categories»
echo $en->singularize('mice'); // «mouse»
$ru = new Inflector(Language::Russian);
echo $ru->decline('город', GrammaticalCase::Genitive); // «города»
echo $ru->pluralizeByCount('город', 5); // «городов» (согласование с числом)
// Транслитерация в обе стороны.
echo $ru->toLatin('Москва'); // «Moskva»
echo $ru->toCyrillic('Moskva'); // «Москва»
// Числа прописью и обратно (все 8 языков, целые со знаком и десятичные дроби).
echo $ru->numberToWords(125); // «сто двадцать пять»
echo $ru->numberToWords(378.56); // «триста семьдесят восемь целых пятьдесят шесть сотых»
echo $ru->wordsToNumber('тысяча двадцать'); // 1020
Возможности
На каждую возможность есть отдельная страница с диаграммой работы, таблицей сравнения с пятью аналогами и рекомендациями по применению:
| Страница | О чём |
|---|---|
| Число существительных | множественное и единственное число, согласование с числительным |
| Склонение по падежам | 6 падежей обоих чисел, беглые гласные |
| Спряжение глаголов | время, лицо, число, родовые формы прошедшего |
| Числа прописью | число словами и обратный разбор, дроби |
| Форматирование дат | даты и календарные названия на 8 языках |
| Транслитерация и слаги | обратимая пара кириллица ↔ латиница, URL-слаги |
| Преобразования имён | camelize, underscore, tableize, classify |
| Определение рода и языка | род слова и имени, язык текста |
| Пользовательские правила | свои нерегулярные пары и правила-регулярки |
| Архитектура | слои, порядок источников форм, кэши |
| Сравнение с аналогами | автогенерируемые таблицы по шести срезам |
- 8 языков: русский, английский, немецкий, французский, испанский, польский, болгарский, румынский.
- Множественное число / единственное (
pluralize/singularize). - Склонение по 6 падежам (
decline) и склонение имён/фамилий. - Спряжение глаголов по временам (
conjugate). - Согласование с числительными (
pluralizeByCount): 1 город / 2 города / 5 городов. - Правила формы множественного числа (
PluralRules): по локали и количеству — индекс формы для строк видаодин|несколько|многои CLDR-категория (PluralCategory: one/few/many/other). Единый источник правды для инфлексии и внешних потребителей (например, переводчика сообщений). - Числа прописью и обратно (
numberToWords/wordsToNumber): целые со знаком и десятичные дроби на всех 8 языках, с учётом рода и падежей (русский), немецкого словослияния, французской вигезимальной системы, испанских стяжений и множественных форм масштабов (польский/болгарский/румынский). Отдельный публичныйNumberConverter. - Определение рода слова и имени, определение языка текста.
- Транслитерация латиница↔кириллица в обе стороны (обратимо).
- Форматирование дат (
formatDate/formatDateTime) на всех 8 языках: локальный порядок и падеж месяца — «5 марта 2024 года», «5. März 2024», «5 de marzo de 2024». - Календарные названия (
monthName/weekdayName) — месяцы и дни недели языка напрямую, в любом падеже; нумерация дней по ISO-8601, как форматNуdate().
Примеры по возможностям
Множественное и единственное число
$en = new Inflector(Language::English);
$en->pluralize('analysis'); // «analyses»
$en->pluralize('child'); // «children»
$en->singularize('geese'); // «goose»
$ru = new Inflector(Language::Russian);
$ru->pluralize('стол'); // «столы»
$ru->singularize('окна'); // «окно»
Склонение по падежам и согласование с числом
use CloudCastle\Inflector\GrammaticalCase;
$ru = new Inflector(Language::Russian);
$ru->decline('книга', GrammaticalCase::Dative); // «книге»
$ru->decline('Москва', GrammaticalCase::Prepositional); // «Москве»
// Беглая гласная: словарь для непредсказуемых, эвристика для продуктивного «-ец».
$ru->decline('отец', GrammaticalCase::Genitive); // «отца» (не «отеца»)
$ru->decline('угол', GrammaticalCase::Genitive); // «угла»
$ru->decline('любовь', GrammaticalCase::Genitive); // «любви»
// Согласование существительного с количеством.
$ru->pluralizeByCount('город', 1); // «город»
$ru->pluralizeByCount('город', 3); // «города»
$ru->pluralizeByCount('город', 12); // «городов»
Спряжение глаголов
use CloudCastle\Inflector\Tense;
use CloudCastle\Inflector\Person;
use CloudCastle\Inflector\GrammaticalNumber;
$ru = new Inflector(Language::Russian);
$ru->conjugate('идти', Tense::Past, Person::Third, GrammaticalNumber::Singular); // «шёл»
Правила множественного числа (CLDR)
use CloudCastle\Inflector\PluralRules;
use CloudCastle\Inflector\PluralCategory;
PluralRules::index('ru', 5); // 2 — форма «много» (пять рублей)
PluralRules::category('ru', 2); // PluralCategory::Few
PluralRules::category('en', 1); // PluralCategory::One
Единый источник правды: тот же PluralRules используют и pluralizeByCount,
и внешние потребители — например, cloud-castle/translator.
Числа прописью и обратно (8 языков)
$ru = new Inflector(Language::Russian);
$ru->numberToWords(2024); // «две тысячи двадцать четыре»
$ru->numberToWords(-5); // «минус пять»
$ru->wordsToNumber('сто двадцать пять'); // 125
$de = new Inflector(Language::German);
$de->numberToWords(125); // «einhundertfünfundzwanzig»
$fr = new Inflector(Language::French);
$fr->numberToWords(99); // «quatre-vingt-dix-neuf»
Форматирование дат (8 языков)
use CloudCastle\Inflector\GrammaticalCase;
$ru = new Inflector(Language::Russian);
$ru->formatDate(5, 3, 2024); // «5 марта 2024 года»
$ru->formatDate(8, 3, null, GrammaticalCase::Dative); // «8 марту»
$ru->formatDateTime(new DateTimeImmutable('2024-12-31')); // «31 декабря 2024 года»
(new Inflector(Language::German))->formatDate(5, 3, 2024); // «5. März 2024»
(new Inflector(Language::Spanish))->formatDate(5, 3, 2024); // «5 de marzo de 2024»
(new Inflector(Language::Polish))->formatDate(5, 3, 2024); // «5 marca 2024»
(new Inflector(Language::French))->formatDate(1, 1, 2024); // «1er janvier 2024»
Названия месяцев и дней недели
$ru = new Inflector(Language::Russian);
$ru->monthName(3); // «март»
$ru->monthName(3, GrammaticalCase::Genitive); // «марта»
$ru->weekdayName(1); // «понедельник»
$ru->weekdayName(3, GrammaticalCase::Genitive); // «среды»
(new Inflector(Language::Polish))->monthName(3); // «marzec» (в дате — «marca»)
(new Inflector(Language::German))->weekdayName(6); // «Samstag»
Определение рода, языка и транслитерация
$ru = new Inflector(Language::Russian);
// Род существительного: словарь, затем эвристика по окончанию.
$ru->gender('стол'); // Gender::Masculine
$ru->gender('книга'); // Gender::Feminine
$ru->gender('окно'); // Gender::Neuter
$ru->gender('рубль'); // Gender::Masculine (муж. на «-ь»)
// Пол по личному имени (в любой словоформе).
$ru->genderOfName('Мария'); // Gender::Feminine
$ru->genderOfName('Алексей'); // Gender::Masculine
// Определение языка текста (в авто-режиме, без фиксации языка).
(new Inflector())->detectLanguage('Привет'); // Language::Russian
$ru->toLatin('Щёлково'); // «Shchyolkovo»
$ru->toCyrillic('Shchyolkovo'); // «Щёлково»
Справочник API
Все публичные методы фасада Inflector. Подробности и примеры — на страницах
возможностей выше.
| Метод | Что делает |
|---|---|
pluralize(string): string | множественное число |
singularize(string): string | единственное число |
pluralizeByCount(string, int): string | форма, согласованная с числом (1 товар / 2 товара / 5 товаров) |
decline(string, GrammaticalCase, GrammaticalNumber): string | падежная форма слова |
declineName(string, GrammaticalCase): string | падежная форма личного имени |
conjugate(string, Tense, Person, GrammaticalNumber, ?Gender): string | форма глагола |
gender(string): ?Gender | грамматический род слова |
genderOfName(string): ?Gender | грамматический род имени |
detectLanguage(string): Language | язык произвольного текста |
formatDate(int, int, ?int, GrammaticalCase): string | дата по нормам языка |
formatDateTime(DateTimeInterface, GrammaticalCase): string | то же из объекта даты |
monthName(int, GrammaticalCase): string | название месяца |
weekdayName(int, GrammaticalCase): string | название дня недели (ISO-8601) |
numberToWords(string\|int\|float): string | число прописью |
wordsToNumber(string): int\|float | обратный разбор в число |
ordinalize(int): string | порядковое числительное целиком (3rd) |
ordinal(int): string | только суффикс порядкового (rd) |
transliterate(string): string | транслитерация с автовыбором направления |
toLatin(string): string | кириллица в латиницу |
toCyrillic(string): string | латиница в кириллицу |
slugify(string, string): string | URL-слаг с транслитерацией |
camelize(string): string | foo_bar в fooBar |
pascalize(string): string | foo_bar в FooBar |
underscore(string): string | FooBar в foo_bar |
dasherize(string): string | foo_bar в foo-bar |
tableize(string): string | класс в имя таблицы (FooBar в foo_bars) |
classify(string): string | имя таблицы в класс (foo_bars в FooBar) |
titleize(string): string | foo_bar в Foo Bar |
humanize(string): string | foo_bar_id в Foo bar |
capitalize(string): string | первая буква заглавной |
addIrregular(string, string): self | своя нерегулярная пара |
addUncountable(string): self | своё неисчисляемое слово |
addPluralRule(string, string): self | своё правило множественного числа |
addSingularRule(string, string): self | своё правило единственного числа |
Методы add* возвращают сам инфлектор — вызовы связываются в цепочку — и
сбрасывают кэши, чтобы форма не пережила замену правил.
Сравнение с аналогами
Все таблицы ниже сгенерированы автоматически из честных сравнительных
тестов (benchmarks/compare.php) на ОДИНАКОВОЙ операции для всех аналогов,
PHP 8.3.32, без Xdebug.
1. Функциональность
| Возможность | 🏆 CloudCastle | doctrine | symfony | icanboogie | cakephp | illuminate | наивно¹ |
|---|---|---|---|---|---|---|---|
| Число: pluralize + singularize | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| Регистр: camelize/classify/tableize/underscore | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| Порядковые числительные (ordinalize) | ✅ | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ |
| Slugify с транслитерацией (Unicode → ASCII) | ✅ | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ |
| Многоязычность с грамматическими падежами | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Склонение с беглой гласной (отец → отца) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Форматирование дат с падежом месяца (8 языков) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Всего | 🏆 7 | 2 | 3 | 3 | 3 | 4 | 0 |
2. Безопасность и корректность
| Свойство | 🏆 CloudCastle | doctrine | symfony | icanboogie | cakephp | illuminate | наивно¹ |
|---|---|---|---|---|---|---|---|
| Правильная форма: phenomenon → phenomena | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
| Правильная форма: index → indices | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ | ❌ |
| Правильная форма: matrix → matrices | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ |
| Правильная форма: cactus → cacti | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ |
| Правильная форма: criterion → criteria | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ |
| Всего | 🏆 5 | 4 | 3 | 2 | 3 | 4 | 0 |
3. Производительность
Образование мн. числа 20 слов, 40 000 раз (минимум из 4).
| Решение | Время (мс) | Итог |
|---|---|---|
| 🏆 CloudCastle | 161,3 | быстрейшее среди библиотек |
| doctrine | 213,7 | аналог |
| cakephp | 265 | аналог |
| наивно¹ | 265 | базовый уровень (не библиотека) |
| illuminate | 1 192,2 | аналог |
| symfony | 5 407,6 | аналог |
| icanboogie | 9 682,1 | аналог |
4. Потребление памяти
Собственный след библиотеки на 40 000 операций (изолированный процесс, дельта к baseline без библиотеки).
| Решение | Пиковая память (KB) | Итог |
|---|---|---|
| наивно¹ | 0 | базовый уровень (не библиотека) |
| 🏆 cakephp | 6 | легчайшее среди библиотек |
| symfony | 62 | аналог |
| icanboogie | 103 | аналог |
| CloudCastle | 386 | аналог |
| doctrine | 452 | аналог |
| illuminate | 722 | аналог |
5. Утечки памяти
Рост памяти на второй волне из 20 000 новых уникальных слов после такой же первой (0 — библиотека не течёт).
| Решение | Рост памяти (KB) | Итог |
|---|---|---|
| 🏆 CloudCastle | 0 | не течёт (рост 0) |
| symfony | 0 | аналог |
| icanboogie | 0 | аналог |
| наивно¹ | 0 | базовый уровень (не библиотека) |
| doctrine | 2 843 | аналог |
| cakephp | 2 843 | аналог |
| illuminate | 2 843 | аналог |
6. Качество кода
| Критерий | 🏆 CloudCastle | doctrine | symfony | icanboogie | cakephp | illuminate | наивно¹ |
|---|---|---|---|---|---|---|---|
| Строгая типизация во всех файлах (declare(strict_types=1)) | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Типы возвращаемых значений у всех публичных методов | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Требует современный PHP 8.1+ | ✅ | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ |
| Без сторонних runtime-зависимостей (кроме PSR/ext/cloud-castle) | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ |
| Не течёт на потоке уникальных слов | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ✅ |
| Всего | 🏆 5 | 3 | 2 | 2 | 1 | 1 | 1 |
¹ Базовый уровень (нативные вызовы/примитивы без полноты решения) показан для контекста и не претендует на победу среди библиотек-аналогов.
Таблица «Корректность форм» построена на реальных вызовах: на трудных словах
(phenomenon, index, matrix, cactus, criterion) алгоритмические инфлекторы
расходятся, а cloud-castle/inflector точен благодаря правилам с лексиконом
исключений. Память измеряется как собственный след библиотеки: в изолированном
процессе (только целевая библиотека) из результата вычитается baseline — тот же
процесс с автозагрузчиком, данными и прогретым циклом, но без единого класса
библиотеки. Поэтому в таблице стоит потребление самой библиотеки, а не
интерпретатора PHP и харнесса замера. Утечки проверяются двумя волнами по
20 000 новых уникальных слов: библиотека с ограниченным кэшем держит память
на месте, с неограниченным — растёт линейно. Признаки качества кода читаются
из исходников установленных пакетов, а не из заявлений авторов.
Вывод: CloudCastle Inflector — самый быстрый среди аналогов и функционально
богатейший: помимо множественного числа он склоняет по падежам, спрягает глаголы,
образует порядковые, делает slugify с транслитерацией и работает с восемью языками —
при единственной зависимости (словарь cloud-castle/dictionary).
Плата за это — собственный след памяти (≈390 KB) выше, чем у англо-центричных
минималистов: cakephp (6 KB), symfony (86 KB) и icanboogie (103 KB) решают только
английское число, тогда как пакет держит в памяти правила и словари восьми языков.
Против сопоставимого по охвату illuminate/support (731 KB) он почти вдвое легче.
Это осознанный компромисс: функциональностью, скоростью, отсутствием утечек и
корректностью мы не жертвуем ради килобайтов.
Плюсы, минусы и когда применять
Сильные стороны:
- Восемь языков в одном пакете с грамматическими падежами, спряжением и числами прописью — то, чего нет у англо-центричных аналогов.
- Единственная зависимость (
cloud-castle/dictionary— словарь выверенных словоформ той же экосистемы), PHP 8.1+, строгая типизация, 100 % покрытие и MSI. - Быстрейший среди аналогов на общей операции — заметно быстрее doctrine, cakephp, illuminate, symfony и icanboogie (см. таблицы выше).
- Не течёт: кэши ограничены, поэтому на потоке уникальных слов память стоит на месте, тогда как doctrine, cakephp и illuminate растут неограниченно.
- Корректные формы трудных английских слов за счёт лексикона исключений.
Ограничения (честно):
- Определение рода (
gender()) для русского использует словарь + эвристику по окончанию и покрывает подавляющее большинство слов; редкие исключения на «-ь» (мужской/женский род) разрешаются по встроенному списку, но он не исчерпывающий. Для других языков родовой эвристики нет (возвращаетсяnull). - Морфология польского/болгарского/румынского покрывает частотные правила, но не все нерегулярные случаи (приближения помечены в PHPDoc правил).
- Собственный след памяти (≈390 KB) выше, чем у англо-центричных минималистов —
cakephp (6 KB), symfony (86 KB), icanboogie (103 KB): пакет держит правила и
словари восьми языков. Против сопоставимого по охвату
illuminate/support(731 KB) — почти вдвое легче. Компромисс осознанный: функциональностью, скоростью, отсутствием утечек и корректностью ради килобайтов не жертвуем. - Склонение существительных с беглой гласной (отец → отца, угол → угла, любовь →
любви) опирается на словарь
cloud-castle/dictionary: частотная лексика склоняется точно, но словарь не исчерпывающий — редкое слово с беглой гласной вне словаря просклоняется по регулярной парадигме, без выпадения гласной. Продуктивный тип на «-ец» (юнец → юнца) выводится правилом и работает без словаря. - Транслитерация рассчитана на пару латиница↔кириллица, а не на любые письменности.
Когда применять: генерация человекочитаемых подписей и сообщений (счётчики «5 товаров»), склонение имён в письмах/документах, число прописью в платёжных документах, slug-и для URL, мультиязычные интерфейсы. Когда не стоит: если нужна полноценная лемматизация/морфоанализатор научного уровня — возьмите специализированный NLP-инструмент.
Разработка
composer install
composer check # линтеры + статический анализ + тесты
composer fix # автоисправления (Rector, PHP CS Fixer, PHPCBF)
composer ci # полный CI-пайплайн локально
Полный список команд с описаниями: composer run-script --list.
Документация
- Репозиторий: https://gitverse.ru/cloud-castle/inflector
- История изменений: CHANGELOG.md
- Как внести вклад: CONTRIBUTING.md
- Кодекс поведения: CODE_OF_CONDUCT.md
- Политика безопасности: SECURITY.md
Лицензия
MIT © CloudCastle (alex-4-17@yandex.ru)
🇷🇺 Русский · 🇬🇧 English · 🇩🇪 Deutsch · 🇫🇷 Français · 🇪🇸 Español · 🇮🇹 Italiano