Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 35
0.00% covered (danger)
0.00%
0 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
Hooks
0.00% covered (danger)
0.00%
0 / 35
0.00% covered (danger)
0.00%
0 / 2
110
0.00% covered (danger)
0.00%
0 / 1
 onLanguageGetTranslatedLanguageNames
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 onGetHumanTimestamp
0.00% covered (danger)
0.00%
0 / 34
0.00% covered (danger)
0.00%
0 / 1
90
1<?php
2
3namespace MediaWiki\Extension\CLDR;
4
5use Language;
6use MediaWiki\Hook\GetHumanTimestampHook;
7use MediaWiki\Languages\Hook\LanguageGetTranslatedLanguageNamesHook;
8use MWTimestamp;
9use User;
10
11/**
12 * Hooks for integration into MediaWiki language system
13 *
14 * @license GPL-2.0-or-later
15 */
16class Hooks implements
17    LanguageGetTranslatedLanguageNamesHook,
18    GetHumanTimestampHook
19{
20
21    /**
22     * @param array &$names
23     * @param string $code
24     */
25    public function onLanguageGetTranslatedLanguageNames( &$names, $code ): void {
26        $names += LanguageNames::getNames( $code, LanguageNames::FALLBACK_NORMAL, LanguageNames::LIST_MW_AND_CLDR );
27    }
28
29    /**
30     * Handler for GetHumanTimestamp hook.
31     * Converts the given time into a human-friendly relative format, for
32     * example, '6 days ago', 'In 10 months'.
33     *
34     * @param string &$output The output timestamp
35     * @param MWTimestamp $timestamp The current (user-adjusted) timestamp
36     * @param MWTimestamp $relativeTo The relative (user-adjusted) timestamp
37     * @param User $user User whose preferences are being used to make timestamp
38     * @param Language $lang Language that will be used to render the timestamp
39     * @return bool False means the timestamp was overridden so stop further
40     *     processing. True means the timestamp was not overridden.
41     */
42    public function onGetHumanTimestamp( &$output, $timestamp, $relativeTo, $user, $lang ): bool {
43        // Map PHP's DateInterval property codes to CLDR unit names.
44        $units = [
45            's' => 'second',
46            'i' => 'minute',
47            'h' => 'hour',
48            'd' => 'day',
49            'm' => 'month',
50            'y' => 'year',
51        ];
52
53        // Get the difference between the two timestamps (as a DateInterval object).
54        $timeDifference = $timestamp->diff( $relativeTo );
55
56        // Figure out if the timestamp is in the future or the past.
57        if ( $timeDifference->invert ) {
58            $tense = 'future';
59        } else {
60            $tense = 'past';
61        }
62
63        // Figure out which unit (days, months, etc.) it makes sense to display
64        // the timestamp in, and get the number of that unit to use.
65        $unit = null;
66        $number = 0;
67        foreach ( $units as $code => $testUnit ) {
68            $testNumber = (int)$timeDifference->format( '%' . $code );
69            if ( $testNumber > 0 ) {
70                $unit = $testUnit;
71                $number = $testNumber;
72            }
73        }
74
75        // If it occurred less than 1 second ago, output 'just now' message.
76        if ( !$unit || !$number ) {
77            $output = wfMessage( 'just-now' )->inLanguage( $lang )->text();
78            return false;
79        }
80
81        // Get the CLDR time unit strings for the user's language.
82        // If no strings are returned, abandon the timestamp override.
83        $timeUnits = TimeUnits::getUnits( $lang->getCode() );
84        if ( !$timeUnits ) {
85            return true;
86        }
87
88        // Figure out which grammatical number to use.
89        // If the template doesn't exist, fall back to 'other' as the default.
90        $grammaticalNumber = $lang->getPluralRuleType( $number );
91        $timeUnitKey = "{$unit}-{$tense}-{$grammaticalNumber}";
92        if ( !isset( $timeUnits[$timeUnitKey] ) ) {
93            $timeUnitKey = "{$unit}-{$tense}-other";
94        }
95
96        // Not all languages have translations for everything
97        if ( !isset( $timeUnits[$timeUnitKey] ) ) {
98            return true;
99        }
100
101        // Select the appropriate template for the timestamp.
102        $timeUnit = $timeUnits[$timeUnitKey];
103        // Replace the placeholder with the number.
104        $output = str_replace( '{0}', $lang->formatNum( $number ), $timeUnit );
105
106        return false;
107    }
108}