icanboogie/inflector
A fast, dependency-free PHP inflector for English words. Pluralize and singularize nouns, and convert between camelCase, snake_case, hyphenated, humanized and title-case forms. Works standalone or with ICanBoogie, with customizable rules and locale support.
This is a plain PHP package (ICanBoogie\Inflector) — there is no Laravel service provider, no config file, and no auto-discovery beyond Composer's PSR-4 autoloading. Treat it as a library you wrap yourself.
composer require icanboogie/inflector
Where to look first:
ICanBoogie\Inflector — the static facade. It exposes pluralize, singularize, camelize, underscore, humanize, hyphenate, titleize, slugize, and format.Inflector::get($locale) — returns a per-locale instance. The multilingual support (the main reason to pick this over Laravel's Str) lives here, backed by locale data files shipped with the package.First use case — poke it in Tinker:
use ICanBoogie\Inflector;
Inflector::pluralize('child'); // children
Inflector::singularize('people'); // person
Inflector::camelize('user_profile'); // userProfile
Inflector::underscore('UserProfile'); // user_profile
Inflector::humanize('line_items'); // Line items
Inflector::format('Hello {name}', ['name' => 'World']); // Hello World
Before writing any code, audit what you actually need. Laravel's Str::plural, Str::camel, Str::slug, and Str::headline already cover most English single-locale cases. Reach for this package when you need (a) non-English pluralization/singularization, or (b) the {placeholder}-style format() helper. If neither applies, you're adding a dependency for nothing.
Wrap it in a container binding. Because there's no provider, register one yourself so the locale follows the app locale and the instance is reused:
// app/Providers/AppServiceProvider.php
$this->app->singleton('inflector', function ($app) {
$locale = $app->getLocale();
try {
return \ICanBoogie\Inflector::get($locale);
} catch (\Throwable $e) {
return \ICanBoogie\Inflector::get('en'); // graceful fallback
}
});
// helper
function inflector(): \ICanBoogie\Inflector {
return app('inflector');
}
Multi-locale pattern. The inflector instance is immutable per locale, so don't share one across a locale switch mid-request. If you're generating localized UI strings in a loop, capture the instance once:
$inflector = \ICanBoogie\Inflector::get(app()->getLocale());
$labels = collect($columns)
->mapWithKeys(fn ($col) => [$col => $inflector->humanize($col)]);
Model / CRUD label generation. The most natural day-to-day use: turning table or column names into admin-panel labels without a translation key for every field.
$label = inflector()->humanize($model->getTable()); // "Line items"
$title = inflector()->titleize($model->getTable());
Naming conventions for generated code. Use camelize/underscore consistently when generating job, policy, or resource class names from a table name:
$base = inflector()->camelize(inflector()->singularize($table), true);
$jobClass = "Generate{$base}Report";
Templated strings from the database. format() shines for user-editable templates (email subjects, notification bodies) stored with {named} placeholders rather than positional sprintf args:
$subject = inflector()->format(
$template->subject, // "Your order {order_number} shipped"
['order_number' => $order->number]
);
Blade exposure. If templates need it, register a directive rather than calling a helper in 40 views:
Blade::directive('inflect', fn ($expr) => "<?php echo e(inflector()->humanize($expr)); ?>");
Testing pattern. Swap the binding in tests for a stub or a fixed-locale instance so assertions don't depend on app()->getLocale():
$this->app->instance('inflector', \ICanBoogie\Inflector::get('en'));
Str. Pick one convention per codebase. Mixing Str::plural() and Inflector::pluralize() will eventually disagree on irregulars (person, datum, uncountables like news), producing route names or labels that don't match the tables Laravel migrations created.$table->increments conventions or your own Str::plural, feeding it back into pluralize() can produce newses or people_s style artifacts. Decide singular-in, plural-out and stick to it.Inflector::get('fr') caches instances statically. If your middleware sets the locale after the binding resolves, you'll get the wrong language — resolve inside the request, not at boot, or pass the locale explicitly.format() placeholder syntax collides. {name} is not :name (Laravel translations) and not {{ }} (Blade). Don't run format() output through Blade compilation, and don't mix placeholder styles in the same template store.camelize won't know that api should be API in ApiClient. For acronym-heavy class names, post-process or keep using Str::studly with your own mapping.new Inflector() per iteration re-reads locale data. Bind once, resolve once per request.addIrregular() API. If you need custom inflections, decorate the package: a small class AppInflector { public function __construct(private Inflector $inner) {} } with an override table is cleaner than subclassing internals.LICENSE file manually before shipping in a commercial product.composer.json.How can I help you explore Laravel packages today?