Page MenuHomePhabricator

MUL - Use `mul` Labels as placeholders for missing values in the desktop termbox [part 1 of 2: when viewing]
Closed, DuplicatePublic13 Estimated Story Points

Description

Problem:
Instead of adding identical values for many languages, editors will soon be able to add a mul Label and Alias in the termbox. It is however not immediately obvious, that the mul entries will work as fallbacks. Editors will only see "No label defined" which might convince some editors to add the redundant Labels again. We need to make this more intuitive.

Notes:

  • In story writing, it was decided to split the original task into viewing (T329655) and editing (T338330).
  • We only consider mul values as intentional fallbacks. So we only use mul values as placeholders and not en values.

Solution:
If a mul label is available, use it as a placeholder for all other existing languages with an empty value.

Mockups:

Group 15.png (764×1 px, 123 KB)

BDD:
The mul Label is used as a placeholder for all empty Labels when the Item is opened for viewing (or editing) on desktop (and mobile).

GIVEN an Item with a mul Label specified
WHEN the Item is opened for viewing (or editing) on desktop (or mobile)
THEN all empty Labels are shown with the mul Label as a placeholder (in gray, see mockups)

Acceptance criteria:
Labels-only in viewing mode!

  • The mul Label is used as a placeholder for all empty Labels when the Item is opened for viewing (or editing) on the desktop (see mockups and BDD).
  • Release to test.wikidata.org

Event Timeline

Manuel renamed this task from MUL - Use `mul` as a placeholders in the termbox to MUL - Use `mul` Labels and Aliases as placeholders for missing values in the termbox .Feb 14 2023, 5:26 PM
Manuel updated the task description. (Show Details)
Manuel updated the task description. (Show Details)
Manuel updated the task description. (Show Details)
Manuel updated the task description. (Show Details)
Manuel renamed this task from MUL - Use `mul` Labels and Aliases as placeholders for missing values in the termbox to MUL - Use `mul` Labels and Aliases as placeholders for missing values in the desktop termbox .Mar 15 2023, 2:08 PM
Manuel updated the task description. (Show Details)
Manuel renamed this task from MUL - Use `mul` Labels and Aliases as placeholders for missing values in the desktop termbox to MUL - Use `mul` Labels and Aliases as placeholders for missing values in the desktop termbox [part 1 of 2: viewing].Jun 7 2023, 2:40 PM
Manuel updated the task description. (Show Details)
Manuel renamed this task from MUL - Use `mul` Labels and Aliases as placeholders for missing values in the desktop termbox [part 1 of 2: viewing] to MUL - Use `mul` Labels and Aliases as placeholders for missing values in the desktop termbox [part 1 of 2: when viewing].Jun 7 2023, 2:46 PM

I had a first look at the code to prepare for story planning:

The code that generates those lines in PHP is in \Wikibase\View\TermsListView::getTermView. However, depending on whether there is at least one Term or no Term at all for a language, that method is reached in two very different ways.

If there is at least one Term for a language:

#0 /var/www/html/w/extensions/Wikibase/view/src/TermsListView.php(122): Wikibase\View\TermsListView->getTermView()
#1 /var/www/html/w/extensions/Wikibase/repo/includes/ParserOutput/PlaceholderEmittingEntityTermsView.php(129): Wikibase\View\TermsListView->getListItemHtml()
#2 /var/www/html/w/extensions/Wikibase/repo/includes/ParserOutput/PlaceholderEmittingEntityTermsView.php(156): Wikibase\Repo\ParserOutput\PlaceholderEmittingEntityTermsView->getTermsListItems()
#3 /var/www/html/w/extensions/Wikibase/view/src/ItemView.php(104): Wikibase\Repo\ParserOutput\PlaceholderEmittingEntityTermsView->getPlaceholders()
#4 /var/www/html/w/extensions/Wikibase/repo/includes/ParserOutput/FullEntityParserOutputGenerator.php(163): Wikibase\View\ItemView->getContent()
#5 /var/www/html/w/extensions/Wikibase/repo/includes/ParserOutput/FullEntityParserOutputGenerator.php(117): Wikibase\Repo\ParserOutput\FullEntityParserOutputGenerator->addHtmlToParserOutput()
#6 /var/www/html/w/extensions/Wikibase/repo/includes/ParserOutput/StatsdTimeRecordingEntityParserOutputGenerator.php(53): Wikibase\Repo\ParserOutput\FullEntityParserOutputGenerator->getParserOutput()
#7 /var/www/html/w/extensions/Wikibase/repo/includes/Content/EntityHandler.php(854): Wikibase\Repo\ParserOutput\StatsdTimeRecordingEntityParserOutputGenerator->getParserOutput()
#8 /var/www/html/w/extensions/Wikibase/repo/includes/Content/ItemHandler.php(305): Wikibase\Repo\Content\EntityHandler->getParserOutputFromEntityView()
#9 /var/www/html/w/extensions/Wikibase/repo/includes/Content/EntityHandler.php(789): Wikibase\Repo\Content\ItemHandler->getParserOutputFromEntityView()
#10 /var/www/html/w/includes/content/ContentHandler.php(1753): Wikibase\Repo\Content\EntityHandler->fillParserOutput()
#11 /var/www/html/w/includes/content/Renderer/ContentRenderer.php(47): ContentHandler->getParserOutput()
#12 /var/www/html/w/includes/Revision/RenderedRevision.php(260): MediaWiki\Content\Renderer\ContentRenderer->getParserOutput()
#13 /var/www/html/w/includes/Revision/RenderedRevision.php(232): MediaWiki\Revision\RenderedRevision->getSlotParserOutputUncached()
#14 /var/www/html/w/includes/Revision/RevisionRenderer.php(227): MediaWiki\Revision\RenderedRevision->getSlotParserOutput()
#15 /var/www/html/w/includes/Revision/RevisionRenderer.php(164): MediaWiki\Revision\RevisionRenderer->combineSlotOutput()
#16 [internal function]: MediaWiki\Revision\RevisionRenderer->MediaWiki\Revision\{closure}()
#17 /var/www/html/w/includes/Revision/RenderedRevision.php(199): call_user_func()
#18 /var/www/html/w/includes/poolcounter/PoolWorkArticleView.php(87): MediaWiki\Revision\RenderedRevision->getRevisionParserOutput()
#19 /var/www/html/w/includes/poolcounter/PoolWorkArticleViewCurrent.php(97): PoolWorkArticleView->renderRevision()
#20 /var/www/html/w/includes/poolcounter/PoolCounterWork.php(166): PoolWorkArticleViewCurrent->doWork()
#21 /var/www/html/w/includes/page/ParserOutputAccess.php(299): PoolCounterWork->execute()
#22 /var/www/html/w/includes/page/Article.php(731): MediaWiki\Page\ParserOutputAccess->getParserOutput()
#23 /var/www/html/w/includes/page/Article.php(541): Article->generateContentOutput()
#24 /var/www/html/w/extensions/Wikibase/repo/includes/Actions/ViewEntityAction.php(82): Article->view()
#25 /var/www/html/w/extensions/Wikibase/repo/includes/Actions/ViewEntityAction.php(57): Wikibase\Repo\Actions\ViewEntityAction->showEntityPage()
#26 /var/www/html/w/includes/MediaWiki.php(559): Wikibase\Repo\Actions\ViewEntityAction->show()

If there is no Term at all for a lanugage:

#0 /var/www/html/w/extensions/Wikibase/view/src/TermsListView.php(116): Wikibase\View\TermsListView->getTermView()
#1 /var/www/html/w/extensions/Wikibase/repo/includes/ParserOutput/PlaceholderExpander/EntityViewPlaceholderExpander.php(200): Wikibase\View\TermsListView->getListItemHtml()
#2 /var/www/html/w/extensions/Wikibase/repo/includes/ParserOutput/PlaceholderExpander/EntityViewPlaceholderExpander.php(155): Wikibase\Repo\ParserOutput\PlaceholderExpander\EntityViewPlaceholderExpander->renderTermBox()
#3 /var/www/html/w/extensions/Wikibase/repo/includes/ParserOutput/PlaceholderExpander/EntityViewPlaceholderExpander.php(134): Wikibase\Repo\ParserOutput\PlaceholderExpander\EntityViewPlaceholderExpander->expandPlaceholder()
#4 /var/www/html/w/extensions/Wikibase/repo/includes/ParserOutput/TextInjector.php(79): Wikibase\Repo\ParserOutput\PlaceholderExpander\EntityViewPlaceholderExpander->getHtmlForPlaceholder()
#5 /var/www/html/w/extensions/Wikibase/repo/includes/Hooks/OutputPageBeforeHTMLHookHandler.php(249): Wikibase\Repo\ParserOutput\TextInjector->inject()
#6 /var/www/html/w/extensions/Wikibase/repo/includes/Hooks/OutputPageBeforeHTMLHookHandler.php(223): Wikibase\Repo\Hooks\OutputPageBeforeHTMLHookHandler->replacePlaceholders()
#7 /var/www/html/w/includes/HookContainer/HookContainer.php(158): Wikibase\Repo\Hooks\OutputPageBeforeHTMLHookHandler->onOutputPageBeforeHTML()
#8 /var/www/html/w/includes/HookContainer/HookRunner.php(2676): MediaWiki\HookContainer\HookContainer->run()
#9 /var/www/html/w/includes/OutputPage.php(2286): MediaWiki\HookContainer\HookRunner->onOutputPageBeforeHTML()
#10 /var/www/html/w/includes/OutputPage.php(2298): OutputPage->addParserOutputText()
#11 /var/www/html/w/includes/page/Article.php(861): OutputPage->addParserOutput()
#12 /var/www/html/w/includes/page/Article.php(767): Article->doOutputFromRenderStatus()
#13 /var/www/html/w/includes/page/Article.php(541): Article->generateContentOutput()
#14 /var/www/html/w/extensions/Wikibase/repo/includes/Actions/ViewEntityAction.php(82): Article->view()
#15 /var/www/html/w/extensions/Wikibase/repo/includes/Actions/ViewEntityAction.php(57): Wikibase\Repo\Actions\ViewEntityAction->showEntityPage()
#16 /var/www/html/w/includes/MediaWiki.php(559): Wikibase\Repo\Actions\ViewEntityAction->show()

In my tests, the second path does not seem to know anything about the terms available...

Also, I have not yet looked at the JS code for the legacy Termbox.

Sprint Planning Notes:

  • There is a potential complexity pitfall, as not all term rows are necessarily aware of all available terms.
ItamarWMDE set the point value for this task to 13.Jun 13 2023, 10:08 AM
ItamarWMDE moved this task from Unified DOT Backlog to Sprint-∞ on the Wikidata Dev Team board.

Task Breakdown Notes

  • As a first step it might be helpful to look into this section of TermListView and see if we can utilize it for this purpose
  • This requires further investigation to find a feasible strategy

Open Question

  • The workflow and use case for aliases is different than the one for labels. Can we scope this task down to cover only labels and create a separate story for aliases? @Manuel

The workflow and use case for aliases is different than the one for labels.

Thank you for noticing, @noarave! I scoped the task down for now until @Sarai-WMDE and I have properly defined the aliases workflow. Depending on the outcome, we will either open a new task or clarify this one.

Manuel renamed this task from MUL - Use `mul` Labels and Aliases as placeholders for missing values in the desktop termbox [part 1 of 2: when viewing] to MUL - Use `mul` Labels as placeholders for missing values in the desktop termbox [part 1 of 2: when viewing].Jun 22 2023, 11:27 AM
Manuel updated the task description. (Show Details)

We are going only with placeholders for Labels in the viewing mode. I have clarified the task accordingly.

Also, we have added limiting the placeholders for Labels and Aliases in both viewing and editing modes to take max 2 lines as a separate task (T340133).

The code that generates those lines in PHP is in \Wikibase\View\TermsListView::getTermView. However, depending on whether there is at least one Term or no Term at all for a language, that method is reached in two very different ways.
[snip]
In my tests, the second path does not seem to know anything about the terms available...

@guergana.tzatchkova and I looked some more into this. The first code path happens for each language that has terms, when Wikibase renders the entity to be put into the parser output. The second code path happens on each page view, for any languages that aren’t in the parser output yet. And because that second code path happens even on cached page views, it tries to avoid loading the real entity if possible, and instead just creates an empty one.

If we add the mul label of an entity as another property to the parser output (just like the rendered termbox rows for the languages with terms get added), then we can later load this information in the hook handler and add it to the otherwise empty “fake” entity. Here’s a sketch of how that could work:

diff --git a/repo/includes/ParserOutput/PlaceholderEmittingEntityTermsView.php b/repo/includes/ParserOutput/PlaceholderEmittingEntityTermsView.php
index 34da4ed8c2..1d9bd9d21a 100644
--- a/repo/includes/ParserOutput/PlaceholderEmittingEntityTermsView.php
+++ b/repo/includes/ParserOutput/PlaceholderEmittingEntityTermsView.php
@@ -155,6 +155,10 @@ public function getPlaceholders(
 					$entity->getDescriptions(),
 					$entity->getAliasGroups()
 				),
+			'wikibase-mul-label' =>
+				$entity->getLabels()->hasTermForLanguage( 'mul' )
+					? $entity->getLabels()->getByLanguage( 'mul' )->getText()
+					: null,
 		];
 	}
 
diff --git a/repo/includes/RepoHooks.php b/repo/includes/RepoHooks.php
index ac1855efbc..a1d0c9a92e 100644
--- a/repo/includes/RepoHooks.php
+++ b/repo/includes/RepoHooks.php
@@ -770,6 +770,12 @@ public static function onOutputPageParserOutput( OutputPage $outputPage, ParserO
 			$outputPage->setProperty( 'wikibase-terms-list-items', $termsListItems );
 		}
 
+		// Set in EntityParserOutputGenerator.
+		$mulLabel = $parserOutput->getExtensionData( 'wikibase-mul-label' );
+		if ( $mulLabel !== null ) {
+			$outputPage->setProperty( 'wikibase-mul-label', $mulLabel );
+		}
+
 		// Used in ViewEntityAction and EditEntityAction to override the page HTML title
 		// with the label, if available, or else the id. Passed via parser output
 		// and output page to save overhead of fetching content and accessing an entity
diff --git a/repo/includes/Hooks/OutputPageBeforeHTMLHookHandler.php b/repo/includes/Hooks/OutputPageBeforeHTMLHookHandler.php
index c318278299..443eb31451 100644
--- a/repo/includes/Hooks/OutputPageBeforeHTMLHookHandler.php
+++ b/repo/includes/Hooks/OutputPageBeforeHTMLHookHandler.php
@@ -13,6 +13,7 @@
 use Wikibase\DataModel\Entity\EntityDocument;
 use Wikibase\DataModel\Entity\EntityId;
 use Wikibase\DataModel\Entity\EntityIdParser;
+use Wikibase\DataModel\Term\LabelsProvider;
 use Wikibase\Lib\ContentLanguages;
 use Wikibase\Lib\EntityFactory;
 use Wikibase\Lib\LanguageFallbackChainFactory;
@@ -272,7 +273,11 @@ private function getEntity( OutputPage $out ) {
 			return $entityRev->getEntity();
 		}
 
-		return $this->entityFactory->newEmpty( $entityId->getEntityType() );
+		$entity = $this->entityFactory->newEmpty( $entityId->getEntityType() );
+		if ( $entity instanceof LabelsProvider && $out->getProperty( 'wikibase-mul-label' ) ) {
+			$entity->getLabels()->setTextForLanguage( 'mul', $out->getProperty( 'wikibase-mul-label' ) );
+		}
+		return $entity;
 	}
 
 	private function needsRealEntity( OutputPage $out ) {
diff --git a/view/src/TermsListView.php b/view/src/TermsListView.php
index 3fd483f714..6e9921ac4a 100644
--- a/view/src/TermsListView.php
+++ b/view/src/TermsListView.php
@@ -112,15 +112,24 @@ public function getListItemHtml(
 	}
 
 	private function getLabelView( TermList $listOfLabelTerms, string $languageCode ): string {
-		$hasLabelInLanguage = $listOfLabelTerms->hasTermForLanguage( $languageCode );
-		$effectiveLanguage = $hasLabelInLanguage ? $languageCode : $this->textProvider->getLanguageOf( 'wikibase-label-empty' );
+		if ( $listOfLabelTerms->hasTermForLanguage( $languageCode ) ) {
+			$labelEntry = $listOfLabelTerms->getByLanguage( $languageCode )->getText();
+			$effectiveLanguage = $languageCode;
+			$isEmpty = false;
+		} elseif ( $listOfLabelTerms->hasTermForLanguage( 'mul' ) ) {
+			$labelEntry = $listOfLabelTerms->getByLanguage( 'mul' )->getText();
+			$effectiveLanguage = 'mul';
+			$isEmpty = true;
+		} else {
+			$this->textProvider->get( 'wikibase-label-empty' );
+			$effectiveLanguage = $this->textProvider->getLanguageOf( 'wikibase-label-empty' );
+			$isEmpty = true;
+		}
+
 		return $this->templateFactory->render(
 			'wikibase-labelview',
-			$hasLabelInLanguage ? '' : 'wb-empty',
-			htmlspecialchars( $hasLabelInLanguage
-				? $listOfLabelTerms->getByLanguage( $languageCode )->getText()
-				: $this->textProvider->get( 'wikibase-label-empty' )
-			),
+			$isEmpty ? 'wb-empty' : '',
+			htmlspecialchars( $labelEntry ),
 			'',
 			$this->languageDirectionalityLookup->getDirectionality( $effectiveLanguage ) ?: 'auto',
 			$effectiveLanguage

In my local testing, that mostly seems to work, though the JS in view/resources/jquery/wikibase/jquery.wikibase.labelview.js also needs to be adjusted for the “all entered languages” to behave the same.

Manuel changed the task status from Open to Stalled.Jun 29 2023, 8:17 AM

Sarai and I recently came across an idea from Bugreporter. As currently described in this task, we would use the mul text as a universal placeholder for missing Labels and Aliases. However, we believe there's room for improvement by applying the fallback chain for each missing language individually.

Here's how this could work: Rather than relying solely on the mul fallback, each placeholder would first attempt to use the translatewiki fallbacks. For example, if there's a missing Austrian Label, it would first try to fall back to the German Label. Only as a final step would it resort to the hardcoded mul fallback. It's important to note that the usual hardcoded en fallback would NOT be applied for placeholders. This change would enhance the accuracy of the placeholders, aligning them better with the actual fallback chain behavior.

We have a couple of questions for you, the Wikidata development team, regarding this idea:

  1. Is it technically feasible to have Label/Alias placeholders run the fallback chain individually for each missing language, instead of relying on the mul values for all, as described in the task?
  2. Would implementing this change significantly increase the complexity of the task?

I stalled this task (as well as T338330) until after our meeting today. If it's feasible to implement this change without significantly increasing the complexity, we will incorporate the necessary modifications and then unstall the tasks again. If the modifications would significantly increase the complexity of the task, we would need to restructure and/or reestimate the task. If it proves to be technically unfeasible, then UX and Product will need to think about an alternative solution.

Manuel changed the task status from Stalled to Open.EditedJul 3 2023, 11:50 AM

I opened this task again: We decided to aim at generally representing the fallback chain in the placeholders (see separate task T340832). This task as described in T329655 will be the basis for this.

Manuel changed the task status from Open to Stalled.Jul 3 2023, 12:59 PM
Manuel changed the task status from Stalled to Open.Jul 4 2023, 11:48 AM
This comment was removed by ItamarWMDE.