aboutsummaryrefslogtreecommitdiffstats
path: root/includes/ResourceLoader
diff options
context:
space:
mode:
authorTim Starling <tstarling@wikimedia.org>2025-03-13 16:37:47 +1100
committerTim Starling <tstarling@wikimedia.org>2025-04-02 14:41:16 +1100
commit09b10c746bbfcbfaeb2d079354ff89039d9da13b (patch)
treed9aae8dbb8bfd27c83ae4ce23d9c13de2626e3d4 /includes/ResourceLoader
parent818c34a316cb5f59fb57fc9dd3bb3103bfcd2116 (diff)
downloadmediawikicore-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.php84
-rw-r--r--includes/ResourceLoader/UserOptionsModule.php12
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";