lorisleiva/cron-translator
Make CRON expressions human-readable in PHP/Laravel. Translate schedules like “*/2 * * * *” into natural language (“Every 2 minutes”), with optional locale and 24-hour time formatting. Supports many languages (en, fr, de, es, etc.).
Installation:
composer require lorisleiva/cron-translator
Add to composer.json under require if using a monorepo or constrained environment.
First Use Case: Translate a cron expression in a Laravel controller or service:
use Lorisleiva\CronTranslator\CronTranslator;
$translated = CronTranslator::translate('0 0 * * *'); // "Every day at 12:00am"
return response()->json(['cron' => $translated]);
Where to Look First:
src/CronTranslator.php: Core logic and supported cron syntax.tests/: Edge cases and validation patterns (e.g., */2, 1-5/3).Admin Panels/Dashboards:
// In a Laravel Blade view
<div class="cron-description">
{{ CronTranslator::translate($job->cronExpression, 'en') }}
</div>
$translated = Cache::remember("cron_{$cron}", now()->addHours(1), function() use ($cron) {
return CronTranslator::translate($cron);
});
API Documentation:
/**
* @OA\Get(
* path="/webhooks/payment",
* summary="Process payment webhook",
* description="{{ CronTranslator::translate('0 9 * * 1-5', 'en') }}"
* )
*/
User-Facing Scheduling Tools:
// Laravel Form Request validation
public function rules()
{
return [
'cron_expression' => [
'required',
'string',
function ($attribute, $value, $fail) {
try {
CronTranslator::translate($value); // Throws on invalid cron
} catch (\InvalidArgumentException $e) {
$fail('Invalid cron expression.');
}
},
],
];
}
Logging/Auditing:
Log::info('Scheduled job triggered', [
'cron' => CronTranslator::translate($job->cron),
'job' => $job->name,
]);
Localization:
$locale = app()->getLocale();
$translated = CronTranslator::translate($cron, $locale);
true as the third argument:
CronTranslator::translate('30 18 * * *', 'fr', true); // "Chaque jour à 18:30"
Laravel Service Providers:
// app/Providers/AppServiceProvider.php
public function register()
{
$this->app->singleton(CronTranslator::class);
}
public function __construct(private CronTranslator $translator) {}
Testing:
public function testCronTranslation()
{
$this->assertEquals(
'Every minute',
CronTranslator::translate('* * * * *')
);
}
*/2, 1-5/3) from the package’s test suite.Extended Cron Support:
*/2), ranges (1-5), lists (1,2,3), and comma-separated weekdays (1,2,3,4,5). Validate inputs against these patterns before translation.Unsupported Cron Syntax:
L (last day of the month)W (nearest weekday)? (no specific value, used in Quartz-style cron)* * * * * 2025).Locale Fallback:
en. Always handle fallbacks:
try {
$translated = CronTranslator::translate($cron, $locale);
} catch (\InvalidArgumentException $e) {
$translated = CronTranslator::translate($cron); // Fallback to English
}
Performance:
1,2 0 */2 1,2 *) can be CPU-intensive for large batches. Cache results aggressively:
Cache::forever("cron_{$cron}_{$locale}", $translated);
Time Format Quirks:
24-hour flag (true) only affects the time portion of the output. Dates (e.g., "January 1st") remain in locale-specific formats.Weekday Ambiguity:
0-6 for weekdays (0 = Sunday). The package handles this internally, but user inputs (e.g., forms) should validate against 0-6 or 1-7 (if using 1 = Monday).Invalid Cron Expressions:
\InvalidArgumentException for malformed cron strings. Catch and log these for debugging:
try {
$translated = CronTranslator::translate($cron);
} catch (\InvalidArgumentException $e) {
Log::error("Invalid cron '{$cron}': " . $e->getMessage());
throw new \RuntimeException('Invalid cron expression.');
}
Unexpected Output:
1-3/5 * * * *), verify the output against crontab.guru or the Vixie cron format.1-3/5 * * * * translates to "3 times every 5 minutes" (not "every 5 minutes from 1 to 3").Locale-Specific Issues:
ar, hi) may render dates in unexpected formats. Test with real user locales early:
// Test all supported locales
$locales = ['en', 'fr', 'ar', 'zh', 'pt'];
foreach ($locales as $locale) {
echo CronTranslator::translate('0 0 * * *', $locale) . "\n";
}
Custom Locales:
// app/Services/CustomCronTranslator.php
use Lorisleiva\CronTranslator\CronTranslator as BaseTranslator;
class CustomCronTranslator extends BaseTranslator
{
public static function translate(string $cron, string $locale = 'en', bool $use24HourFormat = false): string
{
// Add custom logic here (e.g., override translations)
return parent::translate($cron, $locale, $use24HourFormat);
}
}
Cron Validation:
spatie/cron-expression for validation:
use Spatie\CronExpression\CronExpression;
public function validateCron(string $cron): void
{
if (!CronExpression::isValidExpression($cron)) {
throw new \InvalidArgumentException('Invalid cron expression.');
}
}
Laravel Artisan Commands:
// app/Console/Commands/TranslateCron.php
use Lorisleiva\CronTranslator\CronTranslator;
class TranslateCron extends Command
{
protected $signature = 'cron:translate {cron} {--locale= : Language code} {--24-hour : Use 24-hour format}';
protected $description = 'Translate a cron expression to human-readable text';
public function handle()
{
$translated = CronTranslator::translate(
$this->argument('cron'),
$this->option('locale'),
$this->option('24-hour')
);
How can I help you explore Laravel packages today?