Cron Translator
Translate CRON expressions into human-readable text across 20+ languages for PHP applications.
Repository Health
Technical Analysis
Cron Translator is a small PHP library that turns raw CRON expressions like 0 16 * * 1 into plain-language sentences such as “Every Monday at 4:00pm”. It ships with built-in translations for over 20 locales, so the same expression can be rendered in English, French, German, Arabic, Chinese, and more with a single locale argument.
The library is framework-agnostic and requires no configuration: install it via Composer, call CronTranslator::translate() with a cron string, and get back a formatted, grammatically-correct description including pluralization handling for each supported language. It is commonly dropped into admin dashboards, scheduled-task lists, and Laravel/Symfony console command listings to make schedules understandable to non-technical users.
What You Get
- A single static
CronTranslator::translate()entry point that accepts a cron string, an optional locale, and an optional 24-hour time flag - Built-in translation files for 20+ locales (English, French, German, Spanish, Arabic, Hindi, Chinese, and more), each with correct pluralization rules
- Support for special CRON macros like
@daily,@weekly,@monthly,@yearly, and@hourly - A field-parsing layer (
MinutesField,HoursField,DaysOfMonthField,MonthsField,DaysOfWeekField) that classifies each cron field as Once/Every/Increment/Multiple for accurate phrasing - Descriptive exceptions (
CronParsingException,TranslationFileMissingException) for invalid expressions or missing locale files
Common Use Cases
- Displaying human-readable schedule descriptions next to raw CRON expressions in admin dashboards
- Annotating Laravel or Symfony scheduled-command listings so non-technical stakeholders understand when a job runs
- Localizing schedule descriptions for multi-language SaaS products with users across different countries
- Validating and summarizing user-entered CRON expressions in a scheduling UI before saving them
Under The Hood
Architecture Cron Translator is built around a small pipeline: CronTranslator::translate() expands CRON macros (@daily etc.), instantiates a CronExpression that splits the raw string into five Field subclasses (minute, hour, day, month, weekday), classifies each field’s CronType (Once/Every/Increment/Multiple), and then orderFields() reassembles them into a natural word order — dropping redundant “every” fields when a more specific increment/multiple field is present, and reversing the “once” fields so time-of-day reads before day-of-week. Each Field subclass implements a translate<Type>() method dispatched dynamically via method_exists, keeping per-field-type phrasing logic isolated (src/MinutesField.php, src/HoursField.php, etc.).
Tech Stack Pure PHP 8.0+ with zero runtime dependencies — composer.json declares only php: ^8.0 in require and phpunit/phpunit: ^9.5 as a dev dependency. Translations are plain PHP arrays loaded via include from src/lang/<locale>/{days,fields,months,ordinals,times}.php, keeping the library dependency-free and fast to autoload via PSR-4.
Code Quality The library has strong test coverage relative to its size: 17 test files under tests/, including a dedicated pluralization test (PluralizeTest.php) and per-locale translation tests (CronTranslatorFRTest.php, CronTranslatorDETest.php, CronTranslatorZHTest.php, and 12 more), each asserting dozens of cron-to-sentence mappings. Class and method names are consistent and PHPDoc-annotated throughout. Error handling is deliberate: malformed cron input is caught broadly in translate() and re-thrown as a single CronParsingException, trading granular error messages for a simple, predictable failure mode.
API Design The public API is a single static method call — CronTranslator::translate($cron, $locale, $timeFormat24hours) — with sensible defaults (en locale, 12-hour format), making adoption a one-line change. The trade-off is that all internal classes (Field, CronExpression, CronType, LanguageLoader) are public but undocumented for extension, so consumers who want a new locale or custom field phrasing need to read source rather than follow a documented extension API.