pharaonic/laravel-readable
Laravel Readable adds human-friendly formatting helpers to your Laravel app—turn numbers into 1.2K, dates into "3 days ago", bytes into file sizes, and more, with simple Blade-ready functions.
Install with Composer and let Laravel's package discovery wire it up:
composer require pharaonic/laravel-readable
If the package ships a config file, publish it once so your formatting choices are versioned rather than baked into views:
php artisan vendor:publish --tag=readable-config
Where to look first: open the package's src/ directory and read the service provider. It tells you three things you need before writing code — the facade/root namespace (typically Pharaonic\Laravel\Readable\...), the global helper function names, and the Blade directive aliases. The README covers the headline API but the provider is the source of truth for aliases, and with a small package like this the provider is short enough to read in two minutes. Also check config/readable.php (if present) for locale, date format, and size-unit settings.
First use case: pick one noisy Blade view — an admin index table with a created_at column and a size_in_bytes column — and swap the raw output for readable versions. That gives you an immediate visual win and forces you to confirm the directive syntax and locale behavior before you roll it out everywhere.
Blade directives for presentation only. The natural home for this package is views. Use directives where you'd otherwise chain number_format(), Carbon::diffForHumans(), and a hand-rolled bytes formatter:
<td>{{ $file->name }}</td>
<td>@readableSize($file->size)</td>
<td>@relativeTime($file->created_at)</td>
Keep the raw values in the underlying model/API response; formatting belongs at the edge.
Helpers in controllers and mail/notification classes. For text that isn't rendered from a Blade file — mail subjects, Slack notifications, PDF generation, log messages — use the global helpers or static calls rather than duplicating the logic. This is where the package earns its keep: one consistent "1.4 MB" everywhere instead of three slightly different implementations.
API Resources with a formatted companion field. Don't replace machine-readable values in JSON responses; add alongside them so clients that need precision still have it:
return [
'size' => $this->size, // bytes, for sorting/compute
'size_readable' => readable_size($this->size), // for display
'created_at' => $this->created_at->toIso8601String(),
'created_human'=> readable_relative($this->created_at),
];
This keeps your frontend free to sort numerically while displaying the friendly string.
Model accessors for genuinely repeated cases. If "human duration" appears in six places for the same model, add an accessor (getDurationReadableAttribute) and $appends it. Resist doing this for one-off columns — it bloats serialization and couples your model to a presentation package.
Locale-aware relative times. If the app is multilingual, set the app locale before calling relative-time helpers (usually already handled by a locale middleware). Relative output is only as good as Carbon's translations for that locale, so spot-check the languages you actually support.
Wrap it in a thin presenter if you'll test heavily. A small App\Support\Format class that delegates to the package gives you one seam to mock and one place to change if the dependency is replaced. Worth it on larger codebases; overkill for a five-view CRUD app.
Confirm the exact API before assuming. With 23 stars and a young release cadence, the method names and directive aliases may drift between minor versions. Pin a version in composer.json ("pharaonic/laravel-readable": "^1.0") and reread the changelog before upgrading. A silent rename in a formatting helper produces wrong output, not an exception — which is worse.
Blade directives are compiled and cached. After changing directive-related config, run php artisan view:clear. A stale compiled view is the most common "the config isn't working" report.
Binary vs decimal file sizes. 1 KB is 1000 bytes in some conventions and 1024 in others. Check what the package uses and what your users expect (disk utilities say 1024; marketing copy says 1000). If the package doesn't expose it, the difference on a 4 TB figure is visible enough to matter.
Timezones. Relative times are computed against "now" in the app's timezone. If you store UTC and display in a user timezone, convert before formatting — otherwise "3 hours ago" can be off by the offset.
Rounding thresholds are opinionated. 999,999 bytes rendering as "1000 KB" instead of "1 MB" is a classic off-by-one in hand-rolled formatters; verify the package's boundaries by testing values like 999, 1000, 1023, 1024, and their megabyte equivalents. Write these as a small unit test so a future upgrade can't silently regress them.
Negatives and zero. Test 0, -1, and null. Zero bytes and zero seconds often produce awkward output ("0 B" is fine; "0 seconds ago" less so). Decide whether null dates should render an em dash and handle that at the call site.
Static methods are hard to mock. If you're asserting exact formatted strings in tests, test the formatter output directly rather than through a controller — it's more stable and doesn't require faking static calls.
Escape deliberately. Formatted output is generally safe, but if you ever route user-controlled strings through it, use {{ }} rather than {!! !!}.
Extension point: if the package's static API doesn't cover a format you need, keep your custom formats in your own helper file rather than forking. Forking a 23-star package means you own the maintenance forever.
How can I help you explore Laravel packages today?