Skip to content

Commit

Permalink
$language arg for DateTimeHelper::humanDuration()
Browse files Browse the repository at this point in the history
Resolves #16332
  • Loading branch information
brandonkelly committed Dec 14, 2024
1 parent 1d89a66 commit 761208f
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 12 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG-WIP.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
## Administration
- The Queue Manager utility now shows jobs’ class names. ([#16228](https://github.com/craftcms/cms/pull/16228))

## Development
- The `|duration` Twig filter now has a `language` argument. ([#16332](https://github.com/craftcms/cms/pull/16332))

## Extensibility
- `craft\helpers\DateTimeHelper::humanDuration()` now has a `$language` argument. ([#16332](https://github.com/craftcms/cms/pull/16332))

## System
- Database rows with foreign keys referencing nonexistent rows are now deleted via garbage collection.
- Pages which contain image transform generation URLs now set no-cache headers. ([#16195](https://github.com/craftcms/cms/discussions/16195))
Expand Down
34 changes: 25 additions & 9 deletions src/helpers/DateTimeHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -759,10 +759,11 @@ public static function isValidIntervalString(string $intervalString): bool
*
* @param mixed $dateInterval The value, represented as either a [[\DateInterval]] object, an interval duration string, or a number of seconds.
* @param bool|null $showSeconds Whether the duration string should include the number of seconds
* @param string|null $language The language code that should be used. (Defaults to the current application language.)
* @return string
* @since 4.2.0
*/
public static function humanDuration(mixed $dateInterval, ?bool $showSeconds = null): string
public static function humanDuration(mixed $dateInterval, ?bool $showSeconds = null, ?string $language = null): string
{
$dateInterval = static::toDateInterval($dateInterval) ?: new DateInterval('PT0S');
$secondsOnly = !$dateInterval->y && !$dateInterval->m && !$dateInterval->d && !$dateInterval->h && !$dateInterval->i;
Expand All @@ -774,24 +775,34 @@ public static function humanDuration(mixed $dateInterval, ?bool $showSeconds = n
$timeComponents = [];

if ($dateInterval->y) {
$timeComponents[] = Craft::t('app', '{num, number} {num, plural, =1{year} other{years}}', ['num' => $dateInterval->y]);
$timeComponents[] = Craft::t('app', '{num, number} {num, plural, =1{year} other{years}}', [
'num' => $dateInterval->y,
], $language);
}

if ($dateInterval->m) {
$timeComponents[] = Craft::t('app', '{num, number} {num, plural, =1{month} other{months}}', ['num' => $dateInterval->m]);
$timeComponents[] = Craft::t('app', '{num, number} {num, plural, =1{month} other{months}}', [
'num' => $dateInterval->m,
], $language);
}

if ($dateInterval->d) {
// Is it an exact number of weeks?
if ($dateInterval->d % 7 === 0) {
$timeComponents[] = Craft::t('app', '{num, number} {num, plural, =1{week} other{weeks}}', ['num' => $dateInterval->d / 7]);
$timeComponents[] = Craft::t('app', '{num, number} {num, plural, =1{week} other{weeks}}', [
'num' => $dateInterval->d / 7,
], $language);
} else {
$timeComponents[] = Craft::t('app', '{num, number} {num, plural, =1{day} other{days}}', ['num' => $dateInterval->d]);
$timeComponents[] = Craft::t('app', '{num, number} {num, plural, =1{day} other{days}}', [
'num' => $dateInterval->d,
], $language);
}
}

if ($dateInterval->h) {
$timeComponents[] = Craft::t('app', '{num, number} {num, plural, =1{hour} other{hours}}', ['num' => $dateInterval->h]);
$timeComponents[] = Craft::t('app', '{num, number} {num, plural, =1{hour} other{hours}}', [
'num' => $dateInterval->h,
], $language);
}

$minutes = $dateInterval->i;
Expand All @@ -806,11 +817,15 @@ public static function humanDuration(mixed $dateInterval, ?bool $showSeconds = n
}

if ($minutes) {
$timeComponents[] = Craft::t('app', '{num, number} {num, plural, =1{minute} other{minutes}}', ['num' => $minutes]);
$timeComponents[] = Craft::t('app', '{num, number} {num, plural, =1{minute} other{minutes}}', [
'num' => $minutes,
], $language);
}

if ($showSeconds && ($dateInterval->s || empty($timeComponents))) {
$timeComponents[] = Craft::t('app', '{num, number} {num, plural, =1{second} other{seconds}}', ['num' => $dateInterval->s]);
$timeComponents[] = Craft::t('app', '{num, number} {num, plural, =1{second} other{seconds}}', [
'num' => $dateInterval->s,
], $language);
}

$last = array_pop($timeComponents);
Expand All @@ -819,10 +834,11 @@ public static function humanDuration(mixed $dateInterval, ?bool $showSeconds = n
if (count($timeComponents) > 1) {
$string .= ',';
}
$string .= ' ' . Craft::t('app', 'and') . ' ';
$string .= ' ' . Craft::t('app', 'and', language: $language) . ' ';
} else {
$string = '';
}

$string .= $last;
return $string;
}
Expand Down
13 changes: 10 additions & 3 deletions tests/unit/helpers/DateTimeHelperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -403,11 +403,16 @@ public function testIsIso8601(bool $expected, mixed $value): void
* @param string $expected
* @param string|int $duration
* @param bool|null $showSeconds
* @param string|null $language
* @throws Exception
*/
public function testHumanDuration(string $expected, string|int $duration, ?bool $showSeconds = null): void
{
self::assertSame($expected, DateTimeHelper::humanDuration($duration, $showSeconds));
public function testHumanDuration(
string $expected,
string|int $duration,
?bool $showSeconds = null,
?string $language = null,
): void {
self::assertSame($expected, DateTimeHelper::humanDuration($duration, $showSeconds, $language));
}

/**
Expand Down Expand Up @@ -871,6 +876,8 @@ public function humanDurationDataProvider(): array
['27 minutes', 'PT10M999S'],
['0 seconds', 0],
['less than a minute', 0, false],
['1,000 years', 'P1000Y', false],
['1 000 ans', 'P1000Y', false, 'fr'],
];
}

Expand Down

0 comments on commit 761208f

Please sign in to comment.