Log duplicate translations of options-messages for HTMLFormField

Why:
* When using a HTMLFormField that has accepts the options-messages
  parameter, the message keys are the key and the value is either
  an array of options or the name of the value.
* However, when converting the message key to the translated text
  it is possible for two or more message keys to have the same
  translation (for example T19746 and T347314). This causes only
  one of the duplicate items to be displayed in the options list.
* As such, an logstash error should be raised when this happens
  so that, when debugging a missing option, the error can be found
  and lead to the issue being found quickly. For example, in
  T347314 it took several months for the issue to be found and
  solved.

What:
* In HTMLFormField::lookupOptionsKeys, add code to check if the
  translated text for the message key already exists in the array
  of translated text to option value. If it does, then create a
  logstash error and skip adding the item to the array (as it
  will override the already added item).
* Also do this in LogEventsList and UsersPager, where the code
  passes the options using the 'options' key and uses the
  HTMLSelectFieldand. This means that HTMLFormField
  ::lookupOptionsKeys will not be called and as such need the
  same code to handle the duplicate values.

Bug: T360326
Change-Id: Ifdeb917f7034967feed7a3b86aabec3c4d49bcc6
This commit is contained in:
Dreamy Jazz 2024-03-21 17:37:57 +00:00 committed by Bartosz Dziewoński
parent a2c16d3d43
commit 294972227e
3 changed files with 44 additions and 3 deletions

View file

@ -10,6 +10,7 @@ use InvalidArgumentException;
use MediaWiki\Context\RequestContext;
use MediaWiki\Html\Html;
use MediaWiki\Linker\Linker;
use MediaWiki\Logger\LoggerFactory;
use MediaWiki\Message\Message;
use MediaWiki\Request\WebRequest;
use MediaWiki\Status\Status;
@ -1261,8 +1262,21 @@ abstract class HTMLFormField {
$ret = [];
foreach ( $options as $key => $value ) {
$msg = $this->msg( $key );
$key = $needsParse ? $msg->parse() : $msg->plain();
$ret[$key] = is_array( $value )
$msgAsText = $needsParse ? $msg->parse() : $msg->plain();
if ( array_key_exists( $msgAsText, $ret ) ) {
LoggerFactory::getInstance( 'error' )->error(
'The option that uses the message key {msg_key_one} has the same translation as ' .
'another option in {lang}. This means that {msg_key_one} will not be used as an option.',
[
'msg_key_one' => $key,
'lang' => $this->mParent ?
$this->mParent->getLanguageCode()->toBcp47Code() :
RequestContext::getMain()->getLanguageCode()->toBcp47Code(),
]
);
continue;
}
$ret[$msgAsText] = is_array( $value )
? $this->lookupOptionsKeys( $value, $needsParse )
: strval( $value );
}

View file

@ -30,6 +30,7 @@ use MediaWiki\HookContainer\HookRunner;
use MediaWiki\Html\Html;
use MediaWiki\Linker\Linker;
use MediaWiki\Linker\LinkRenderer;
use MediaWiki\Logger\LoggerFactory;
use MediaWiki\MainConfigNames;
use MediaWiki\MediaWikiServices;
use MediaWiki\Output\OutputPage;
@ -216,8 +217,21 @@ class LogEventsList extends ContextSource {
// Load the log names
foreach ( LogPage::validTypes() as $type ) {
$page = new LogPage( $type );
$pageText = $page->getName()->text();
if ( in_array( $pageText, $typesByName ) ) {
LoggerFactory::getInstance( 'error' )->error(
'The log type {log_type_one} has the same translation as {log_type_two} for {lang}. ' .
'{log_type_one} will not be displayed in the drop down menu on Special:Log.',
[
'log_type_one' => $type,
'log_type_two' => array_search( $pageText, $typesByName ),
'lang' => $this->getLanguage()->getCode(),
]
);
continue;
}
if ( $this->getAuthority()->isAllowed( $page->getRestriction() ) ) {
$typesByName[$type] = $page->getName()->text();
$typesByName[$type] = $pageText;
}
}

View file

@ -38,6 +38,7 @@ use MediaWiki\HookContainer\HookRunner;
use MediaWiki\Html\Html;
use MediaWiki\HTMLForm\HTMLForm;
use MediaWiki\Linker\Linker;
use MediaWiki\Logger\LoggerFactory;
use MediaWiki\MainConfigNames;
use MediaWiki\Title\Title;
use MediaWiki\User\UserGroupManager;
@ -410,6 +411,18 @@ class UsersPager extends AlphabeticPager {
$groupOptions = [ $this->msg( 'group-all' )->text() => '' ];
foreach ( $this->getAllGroups() as $group => $groupText ) {
if ( array_key_exists( $groupText, $groupOptions ) ) {
LoggerFactory::getInstance( 'error' )->error(
'The group {group_one} has the same translation as {group_two} for {lang}. ' .
'{group_one} will not be displayed in group dropdown of the UsersPager.',
[
'group_one' => $group,
'group_two' => $groupOptions[$groupText],
'lang' => $this->getLanguage()->getCode(),
]
);
continue;
}
$groupOptions[ $groupText ] = $group;
}