lorisleiva/cron-translator
Translate CRON expressions into clear, human-readable schedules. Supports common patterns (ranges, steps, lists) and multiple locales, with optional 24-hour time formatting. Ideal for showing CRON schedules in UIs and logs.
Installation:
composer require lorisleiva/cron-translator
Add to composer.json under require or use require-dev if only for testing.
First Use Case: Translate a cron expression in a Laravel controller or Blade view:
use Lorisleiva\CronTranslator\CronTranslator;
$translated = CronTranslator::translate('0 16 * * 1'); // "Every Monday at 4:00pm"
return view('jobs.index', compact('translated'));
Where to Look First:
src/CronTranslator.php: Core logic and supported cron syntax.tests/: Edge cases and validation patterns.Admin Dashboards: Display human-readable cron schedules next to job listings:
$jobs = Job::all();
foreach ($jobs as $job) {
$job->humanReadableCron = CronTranslator::translate($job->cron);
}
return view('jobs.index', compact('jobs'));
API Documentation: Auto-generate cron descriptions for webhook endpoints:
Route::get('/webhooks', function () {
return [
'webhooks' => [
[
'name' => 'invoice_due',
'cron' => '0 0 1 * *',
'description' => CronTranslator::translate('0 0 1 * *'),
],
],
];
});
User-Facing Scheduling Tools: Localize cron descriptions for non-technical users:
$locale = app()->getLocale(); // e.g., 'fr'
$translated = CronTranslator::translate('30 18 * * *', $locale);
// Output: "Chaque jour à 6:30pm" (French)
Service Provider Binding: Bind the translator to Laravel’s container for dependency injection:
$this->app->singleton(CronTranslator::class, function () {
return new CronTranslator();
});
Then inject via constructor:
public function __construct(private CronTranslator $translator) {}
Blade Directives: Create a custom Blade directive for reusable translations:
Blade::directive('cron', function ($expression) {
return "<?php echo Lorisleiva\CronTranslator\CronTranslator::translate({$expression}); ?>";
});
Usage:
@cron('0 16 * * 1')
Form Validation Feedback: Use translations to explain cron syntax errors:
$validator = Validator::make($request->all(), [
'cron' => 'required|cron',
]);
if ($validator->fails()) {
return back()->withErrors([
'cron' => 'Invalid cron. Example: ' . CronTranslator::translate('* * * * *'),
]);
}
Testing: Mock translations in unit tests:
$translator = Mockery::mock(CronTranslator::class);
$translator->shouldReceive('translate')
->with('0 16 * * 1')
->andReturn('Every Monday at 4:00pm');
$this->app->instance(CronTranslator::class, $translator);
Unsupported Cron Syntax:
@yearly, @monthly) or special characters like L (last day of month) or W (nearest weekday).if (str_contains($cron, '@') || str_contains($cron, 'L')) {
return 'Custom cron syntax (not fully supported)';
}
Locale Fallback:
$supportedLocales = ['en', 'fr', 'de', 'es', 'pt', 'ru', 'zh', 'ar', 'nl'];
$locale = in_array($request->locale, $supportedLocales) ? $request->locale : 'en';
Time Format Ambiguity:
use24h parameter defaults to false. Ensure consistency in your app’s time display settings.Performance:
$cacheKey = "cron_{$cron}_{$locale}";
return Cache::remember($cacheKey, 60, function () use ($cron, $locale) {
return CronTranslator::translate($cron, $locale);
});
Edge Cases:
'1,2 0 */2 1,2 *' // Twice an hour every 2 days 2 months a year at 12am
'1-3/5 * * * *' // 3 times every 5 minutes
Logging:
try {
$translation = CronTranslator::translate($cron);
} catch (\Exception $e) {
Log::warning("Unsupported cron: {$cron}", ['error' => $e->getMessage()]);
$translation = 'Unsupported cron syntax';
}
Custom Extensions:
class ExtendedCronTranslator extends CronTranslator {
public function translate($expression) {
if (str_contains($expression, '@yearly')) {
return 'Yearly (custom)';
}
return parent::translate($expression);
}
}
Locale Prioritization:
config/app.php) does not automatically override the translator’s locale. Always pass the desired locale explicitly:
// Wrong: Assumes app locale
CronTranslator::translate('* * * * *');
// Correct: Explicit locale
CronTranslator::translate('* * * * *', app()->getLocale());
Time Zone Handling:
$cronInUtc = CronExpression::factory($cron)->timezone('UTC')->getExpression();
Testing Locales:
en for tests to avoid flakiness from locale-specific translations:
$this->assertEquals('Every minute', CronTranslator::translate('* * * * *', 'en'));
Add New Locales:
resources/lang/.Custom Translation Rules:
translate() method or use a decorator pattern to modify logic:
class CustomCronTranslator {
public function translate($expression, $locale = 'en', $use24h = false) {
$translation = CronTranslator::translate($expression, $locale, $use24h);
return str_replace('Every', 'Scheduled', $translation); // Customize output
}
}
Integration with Laravel Scheduler:
$schedule = app('schedule');
$jobs = collect($schedule->commands())->map(function ($job) {
return [
'command' => $job,
'description' => CronTranslator::translate($job->expression),
];
});
How can I help you explore Laravel packages today?