diff options
author | Tim Starling <tstarling@wikimedia.org> | 2025-03-13 16:37:47 +1100 |
---|---|---|
committer | Tim Starling <tstarling@wikimedia.org> | 2025-04-02 14:41:16 +1100 |
commit | 09b10c746bbfcbfaeb2d079354ff89039d9da13b (patch) | |
tree | d9aae8dbb8bfd27c83ae4ce23d9c13de2626e3d4 /includes/ResourceLoader | |
parent | 818c34a316cb5f59fb57fc9dd3bb3103bfcd2116 (diff) | |
download | mediawikicore-09b10c746bbfcbfaeb2d079354ff89039d9da13b.tar.gz mediawikicore-09b10c746bbfcbfaeb2d079354ff89039d9da13b.zip |
Client-side date/time formatter library
Add a library providing date/time formatting according to the user's
preferred time zone and date preference.
I tested formatting of an example date with all defined formats in all
languages, and I found that it gives identical output to PHP in about
90% of our ~500 languages.
Resolve some of the outstanding issues by aliasing the problematic date
formats on the client side, so that the user will see the date in
another acceptable format for the same language.
The remaining issues mostly relate to the use of a fallback language to
display weekdays and non-Gregorian month names.
Details:
* Add Language::getJsDateFormats(), which converts existing date formats
to an options array that can be interpreted by the client.
* In Messages*.php, add $numberingSystem, which is the CLDR numbering
system ID. I set it for all languages that had overriden
$digitTransformTable. This is sent to the client in the library's JSON
config and is used as the default numberingSystem option when
formatting dates.
* In Messages*.php, add $jsDateFormats, which overrides the
automatically generated date format options.
Bug: T389161
Change-Id: Ib6bc8ebd4d01317aaf32225c6006ea2dc7a1b39e
Diffstat (limited to 'includes/ResourceLoader')
-rw-r--r-- | includes/ResourceLoader/DateFormatterConfig.php | 84 | ||||
-rw-r--r-- | includes/ResourceLoader/UserOptionsModule.php | 12 |
2 files changed, 96 insertions, 0 deletions
diff --git a/includes/ResourceLoader/DateFormatterConfig.php b/includes/ResourceLoader/DateFormatterConfig.php new file mode 100644 index 000000000000..4fa261532950 --- /dev/null +++ b/includes/ResourceLoader/DateFormatterConfig.php @@ -0,0 +1,84 @@ +<?php + +namespace MediaWiki\ResourceLoader; + +use MediaWiki\Config\Config; +use MediaWiki\Language\Language; +use MediaWiki\Language\LanguageCode; +use MediaWiki\MainConfigNames; +use MediaWiki\MediaWikiServices; + +/** + * @internal + */ +class DateFormatterConfig extends Module { + /** + * Callback for mediawiki.DateFormatter/config.json + * + * @internal + * @param Context $context + * @param Config $config + * @return array + */ + public static function getData( Context $context, Config $config ) { + $lang = MediaWikiServices::getInstance()->getLanguageFactory() + ->getLanguage( $context->getLanguage() ); + return self::getDataForLang( $lang, $config ); + } + + /** + * Get configuration data for DateFormatter given parameters + * + * @internal + * @param Language $lang + * @param Config $config + * @return array + */ + public static function getDataForLang( Language $lang, Config $config ) { + $locales = [ $lang->getHtmlCode() ]; + $fallbacks = $lang->getFallbackLanguages(); + foreach ( $fallbacks as $code ) { + $locales[] = LanguageCode::bcp47( $code ); + } + + // Discover which fields are required + $formats = $lang->getJsDateFormats(); + $haveField = []; + foreach ( $formats as $format ) { + $pattern = $format['pattern'] ?? ''; + foreach ( [ 'mwMonth', 'mwMonthGen', 'mwMonthAbbrev' ] as $field ) { + if ( str_contains( $pattern, "{$field}" ) ) { + $haveField[$field] = true; + } + } + } + + // Include only the required month data + if ( $haveField ) { + $months = [ [] ]; + for ( $i = 1; $i <= 12; $i++ ) { + $data = [ + isset( $haveField['mwMonth'] ) ? $lang->getMonthName( $i ) : '', + isset( $haveField['mwMonthGen'] ) ? $lang->getMonthNameGen( $i ) : '', + isset( $haveField['mwMonthAbbrev'] ) ? $lang->getMonthAbbreviation( $i ) : '' + ]; + // Trim the end of the array + while ( end( $data ) === '' ) { + unset( $data[ array_key_last( $data ) ] ); + } + $months[] = $data; + } + } else { + $months = []; + } + + return [ + 'locales' => $locales, + 'formats' => $formats, + 'defaultStyle' => $lang->getDefaultDateFormat(), + 'localZone' => $config->get( MainConfigNames::Localtimezone ), + 'localOffset' => (int)$config->get( MainConfigNames::LocalTZoffset ), + 'months' => $months + ]; + } +} diff --git a/includes/ResourceLoader/UserOptionsModule.php b/includes/ResourceLoader/UserOptionsModule.php index 383a9905e404..58e74fb9b36f 100644 --- a/includes/ResourceLoader/UserOptionsModule.php +++ b/includes/ResourceLoader/UserOptionsModule.php @@ -2,8 +2,10 @@ namespace MediaWiki\ResourceLoader; +use MediaWiki\MainConfigNames; use MediaWiki\MediaWikiServices; use MediaWiki\User\Options\UserOptionsLookup; +use MediaWiki\User\UserTimeCorrection; /** * This program is free software; you can redistribute it and/or modify @@ -68,6 +70,16 @@ class UserOptionsModule extends Module { unset( $options[ $excludedKey ] ); } + // Update timezone offset (T323193) + if ( isset( $options['timecorrection'] ) ) { + $corr = new UserTimeCorrection( + $options['timecorrection'], + null, + $this->getConfig()->get( MainConfigNames::LocalTZoffset ) + ); + $options['timecorrection'] = $corr->toString(); + } + // Optimisation: Only output this function call if the user has non-default settings. if ( $options ) { $script .= 'mw.user.options.set(' . $context->encodeJson( $options ) . ');' . "\n"; |