Str::plural
Converts an English word to its plural form, returning the singular when the count is exactly one.
Str::plural(string $value, int|array|\Countable $count = 2, bool $prependCount = false): stringParameters
| Parameter | Type | Description |
|---|---|---|
$$value | string | The singular English word to inflect. |
$$countoptional | int|array|Countable= 2 | How many things there are. Arrays and Countable objects are counted first. A count whose absolute value is 1 returns the singular. |
$$prependCountoptional | bool= false | Prefix the result with the count formatted by Number::format, e.g. '1,000 cars'. |
Return value
stringThe pluralised word, or the original word when the count is one, with the original capitalisation preserved.
Errors
With prependCount: true, Number::format throws a RuntimeException when the intl extension is not loaded.
Changelog
- PHP 12.xThe prependCount argument was added; in 11.x and earlier you had to concatenate the count yourself.
Str::plural runs an inflector over the word — English by default — and picks the singular when the count is one, which is the whole reason to use it instead of appending an s. Pass the collection, array or integer you already have and let it decide.
English by default, and never locale-aware
The rules come from doctrine/inflector, which Laravel configures for English out of the box. It is not English-only: the pluralizer also ships french, norwegian-bokmal, portuguese, spanish and turkish, selected with Pluralizer::useLanguage('spanish') in a service provider's boot method. That is a single global setting rather than something that follows the application locale, and switching it means you should define your Eloquent models' table names by hand. Translated interface copy still needs trans_choice() and a pluralisation string in a language file, not this method. Reach for Str::plural for developer-facing output, table names, and UI where you control the vocabulary.
Zero is plural, one is singular
Only an absolute count of exactly 1 returns the singular, so 0 gives "items" and -1 gives "item". That matches English, but it surprises people expecting a zero-specific branch.
Capitalisation is copied, not guessed
The result is matched against the case of the input: an all-lowercase word stays lowercase, an all-uppercase word comes back uppercase, and a capitalised word stays capitalised. Mixed-case input falls through unchanged in case, so iPhone keeps its lowercase i.
A word ending in punctuation is returned untouched, which is why Str::plural('user.') does nothing.
Example
When to use it
- Render '3 comments' or '1 comment' under a post without an inline ternary.
- Generate a table or route name from a model class in a code generator.
- Label a dashboard metric where the unit depends on the value.
Frequently asked questions
How do I show '1 comment' instead of '1 comments' in Laravel?
Pass the count as the second argument: Str::plural('comment', $count) returns the singular whenever the absolute count is 1. Add prependCount: true on Laravel 12 to get the formatted number in front of it.
Does Str::plural work for languages other than English?
It is English by default, but not English-only: Laravel's pluralizer also supports french, norwegian-bokmal, portuguese, spanish and turkish. Switch it application-wide with Pluralizer::useLanguage('spanish') in a service provider's boot method — it is a global setting and does not follow the application locale, and if you change it you should define your Eloquent models' table names explicitly. For interface copy that a translator owns, use trans_choice() with a pluralisation string in a language file instead.
Why did Str::plural return my word unchanged?
Either the count was 1, or the word does not end in a letter or digit — 'user.' and 'user!' are returned verbatim. Strip trailing punctuation before inflecting and add it back afterwards.
More examples
Labelling a count in a view
Passing the collection itself avoids calling count() twice and keeps the label in sync with the data. Note that 0 takes the plural form, which is correct English but differs from languages where zero has its own form.
<?php
use Illuminate\Support\Str;
$counts = [0, 1, 2, 17];
foreach ($counts as $n) {
echo $n, ' ', Str::plural('comment', $n), "\n";
}
// 0 comments
// 1 comment
// 2 comments
// 17 comments
// With a collection, pass it straight in.
$comments = collect(['first']);
echo $comments->count(), ' ', Str::plural('comment', $comments), "\n";
// 1 commentprependCount and its intl requirement
The thousands separator is what you are buying with prependCount, and it is locale-aware via Number::setLocale(). Without ext-intl the first two calls throw a RuntimeException, so the manual form at the bottom is the safer choice in a package.
<?php
use Illuminate\Support\Str;
// Added in Laravel 12. Requires the intl extension,
// because the count goes through Number::format().
echo Str::plural('car', 1000, prependCount: true), "\n";
// 1,000 cars
echo Str::plural('car', 1, prependCount: true), "\n";
// 1 car
// The pre-12 equivalent, with no intl dependency:
$count = 1000;
echo number_format($count), ' ', Str::plural('car', $count), "\n";
// 1,000 carsWhere the inflector will not help you
The first case is the common bug report: the inflector refuses any word not ending in a letter or digit and returns it verbatim. The last line shows the correct tool for localised counts — trans_choice, which needs a booted application and a language file.
<?php
use Illuminate\Support\Str;
// Trailing punctuation short-circuits the whole method.
echo Str::plural('user.'), "\n";
// user.
// Case is matched, not inferred, so mixed case is left alone.
echo Str::plural('iPhone'), "\n";
// iPhones
// Translated copy is not this method's job:
// resources/lang/es/messages.php
// 'comments' => '{0} Sin comentarios|{1} Un comentario|[2,*] :count comentarios',
echo trans_choice('messages.comments', 5, ['count' => 5]);
Discussion