Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
98.61% |
425 / 431 |
|
88.46% |
23 / 26 |
CRAP | |
0.00% |
0 / 1 |
SpecialNewLexeme | |
98.61% |
425 / 431 |
|
88.46% |
23 / 26 |
60 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
20 / 20 |
|
100.00% |
1 / 1 |
1 | |||
factory | |
100.00% |
23 / 23 |
|
100.00% |
1 / 1 |
1 | |||
doesWrites | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
execute | |
100.00% |
72 / 72 |
|
100.00% |
1 / 1 |
3 | |||
getUrlParamsForConfig | |
100.00% |
31 / 31 |
|
100.00% |
1 / 1 |
8 | |||
getItemIdLabelDesc | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
3 | |||
extractLanguageCode | |
82.61% |
19 / 23 |
|
0.00% |
0 / 1 |
7.26 | |||
createExampleParameters | |
100.00% |
17 / 17 |
|
100.00% |
1 / 1 |
3 | |||
createTemplateParamsFromLexemeId | |
100.00% |
37 / 37 |
|
100.00% |
1 / 1 |
5 | |||
processInfoPanelTemplate | |
100.00% |
18 / 18 |
|
100.00% |
1 / 1 |
1 | |||
getLexicalCategorySuggestions | |
100.00% |
22 / 22 |
|
100.00% |
1 / 1 |
3 | |||
termToArrayForJs | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
createForm | |
100.00% |
17 / 17 |
|
100.00% |
1 / 1 |
2 | |||
createEntityFromFormData | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
1 | |||
createSummary | |
100.00% |
11 / 11 |
|
100.00% |
1 / 1 |
1 | |||
redirectToEntityPage | |
100.00% |
16 / 16 |
|
100.00% |
1 / 1 |
3 | |||
newEditEntity | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
1 | |||
saveEntity | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
1 | |||
getFormFields | |
100.00% |
60 / 60 |
|
100.00% |
1 / 1 |
2 | |||
setHeaders | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
getGroupName | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getDescription | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
checkBlocked | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
3 | |||
checkBlockedOnNamespace | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
3 | |||
getCopyrightHTML | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
anonymousEditWarning | |
100.00% |
14 / 14 |
|
100.00% |
1 / 1 |
2 |
1 | <?php |
2 | declare( strict_types = 1 ); |
3 | |
4 | namespace Wikibase\Lexeme\MediaWiki\Specials; |
5 | |
6 | use Exception; |
7 | use Iterator; |
8 | use Liuggio\StatsdClient\Factory\StatsdDataFactoryInterface; |
9 | use MediaWiki\Config\ConfigException; |
10 | use MediaWiki\Html\Html; |
11 | use MediaWiki\Html\TemplateParser; |
12 | use MediaWiki\HTMLForm\HTMLForm; |
13 | use MediaWiki\Language\LanguageCode; |
14 | use MediaWiki\Linker\LinkRenderer; |
15 | use MediaWiki\Message\Message; |
16 | use MediaWiki\SpecialPage\SpecialPage; |
17 | use MediaWiki\Status\Status; |
18 | use MediaWiki\User\TempUser\TempUserConfig; |
19 | use OOUI\IconWidget; |
20 | use UserBlockedError; |
21 | use Wikibase\DataModel\Entity\EntityDocument; |
22 | use Wikibase\DataModel\Entity\EntityId; |
23 | use Wikibase\DataModel\Entity\EntityIdParser; |
24 | use Wikibase\DataModel\Entity\EntityIdParsingException; |
25 | use Wikibase\DataModel\Entity\Item; |
26 | use Wikibase\DataModel\Entity\ItemId; |
27 | use Wikibase\DataModel\Entity\PropertyId; |
28 | use Wikibase\DataModel\Services\Lookup\EntityLookup; |
29 | use Wikibase\DataModel\Snak\PropertySomeValueSnak; |
30 | use Wikibase\DataModel\Snak\PropertyValueSnak; |
31 | use Wikibase\DataModel\Term\Term; |
32 | use Wikibase\DataModel\Term\TermFallback; |
33 | use Wikibase\DataModel\Term\TermList; |
34 | use Wikibase\DataModel\Term\TermTypes; |
35 | use Wikibase\Lexeme\DataAccess\ChangeOp\Validation\LemmaTermValidator; |
36 | use Wikibase\Lexeme\Domain\Model\Lexeme; |
37 | use Wikibase\Lexeme\MediaWiki\Specials\HTMLForm\LemmaLanguageField; |
38 | use Wikibase\Lib\FormatableSummary; |
39 | use Wikibase\Lib\SettingsArray; |
40 | use Wikibase\Lib\Store\EntityNamespaceLookup; |
41 | use Wikibase\Lib\Store\FallbackLabelDescriptionLookup; |
42 | use Wikibase\Lib\Store\FallbackLabelDescriptionLookupFactory; |
43 | use Wikibase\Lib\Summary; |
44 | use Wikibase\Repo\AnonymousEditWarningBuilder; |
45 | use Wikibase\Repo\CopyrightMessageBuilder; |
46 | use Wikibase\Repo\EditEntity\EditEntity; |
47 | use Wikibase\Repo\EditEntity\EditEntityStatus; |
48 | use Wikibase\Repo\EditEntity\MediaWikiEditEntityFactory; |
49 | use Wikibase\Repo\Specials\HTMLForm\HTMLItemReferenceField; |
50 | use Wikibase\Repo\Specials\HTMLForm\HTMLTrimmedTextField; |
51 | use Wikibase\Repo\Specials\SpecialPageCopyrightView; |
52 | use Wikibase\Repo\Store\EntityTitleStoreLookup; |
53 | use Wikibase\Repo\SummaryFormatter; |
54 | use Wikibase\Repo\Validators\ValidatorErrorLocalizer; |
55 | use Wikibase\View\EntityIdFormatterFactory; |
56 | use Wikimedia\Assert\Assert; |
57 | |
58 | /** |
59 | * New page for creating new Lexeme entities. |
60 | * |
61 | * @license GPL-2.0-or-later |
62 | */ |
63 | class SpecialNewLexeme extends SpecialPage { |
64 | |
65 | public const FIELD_LEXEME_LANGUAGE = 'lexeme-language'; |
66 | public const FIELD_LEXICAL_CATEGORY = 'lexicalcategory'; |
67 | public const FIELD_LEMMA = 'lemma'; |
68 | public const FIELD_LEMMA_LANGUAGE = 'lemma-language'; |
69 | |
70 | // used for the info panel and placeholders if the example lexeme is incomplete/missing |
71 | private const FALLBACK_LANGUAGE_LABEL = 'English'; |
72 | private const FALLBACK_LEXICAL_CATEGORY_LABEL = 'verb'; |
73 | |
74 | private array $tags; |
75 | private LinkRenderer $linkRenderer; |
76 | private StatsdDataFactoryInterface $statsDataFactory; |
77 | private MediaWikiEditEntityFactory $editEntityFactory; |
78 | private EntityNamespaceLookup $entityNamespaceLookup; |
79 | private EntityTitleStoreLookup $entityTitleLookup; |
80 | private EntityLookup $entityLookup; |
81 | private EntityIdParser $entityIdParser; |
82 | private SummaryFormatter $summaryFormatter; |
83 | private EntityIdFormatterFactory $entityIdFormatterFactory; |
84 | private FallbackLabelDescriptionLookupFactory $labelDescriptionLookupFactory; |
85 | private ValidatorErrorLocalizer $validatorErrorLocalizer; |
86 | private LemmaTermValidator $lemmaTermValidator; |
87 | private SpecialPageCopyrightView $copyrightView; |
88 | private AnonymousEditWarningBuilder $anonymousEditWarningBuilder; |
89 | private TempUserConfig $tempUserConfig; |
90 | |
91 | public function __construct( |
92 | array $tags, |
93 | SpecialPageCopyrightView $copyrightView, |
94 | LinkRenderer $linkRenderer, |
95 | StatsdDataFactoryInterface $statsDataFactory, |
96 | MediaWikiEditEntityFactory $editEntityFactory, |
97 | EntityNamespaceLookup $entityNamespaceLookup, |
98 | EntityTitleStoreLookup $entityTitleLookup, |
99 | EntityLookup $entityLookup, |
100 | EntityIdParser $entityIdParser, |
101 | SummaryFormatter $summaryFormatter, |
102 | EntityIdFormatterFactory $entityIdFormatterFactory, |
103 | FallbackLabelDescriptionLookupFactory $labelDescriptionLookupFactory, |
104 | ValidatorErrorLocalizer $validatorErrorLocalizer, |
105 | LemmaTermValidator $lemmaTermValidator, |
106 | AnonymousEditWarningBuilder $anonymousEditWarningBuilder, |
107 | TempUserConfig $tempUserConfig |
108 | ) { |
109 | parent::__construct( |
110 | 'NewLexeme', |
111 | 'createpage' |
112 | ); |
113 | |
114 | $this->tags = $tags; |
115 | $this->linkRenderer = $linkRenderer; |
116 | $this->statsDataFactory = $statsDataFactory; |
117 | $this->editEntityFactory = $editEntityFactory; |
118 | $this->entityNamespaceLookup = $entityNamespaceLookup; |
119 | $this->entityTitleLookup = $entityTitleLookup; |
120 | $this->entityLookup = $entityLookup; |
121 | $this->entityIdParser = $entityIdParser; |
122 | $this->summaryFormatter = $summaryFormatter; |
123 | $this->entityIdFormatterFactory = $entityIdFormatterFactory; |
124 | $this->labelDescriptionLookupFactory = $labelDescriptionLookupFactory; |
125 | $this->validatorErrorLocalizer = $validatorErrorLocalizer; |
126 | $this->lemmaTermValidator = $lemmaTermValidator; |
127 | $this->copyrightView = $copyrightView; |
128 | $this->anonymousEditWarningBuilder = $anonymousEditWarningBuilder; |
129 | $this->tempUserConfig = $tempUserConfig; |
130 | } |
131 | |
132 | public static function factory( |
133 | LinkRenderer $linkRenderer, |
134 | StatsdDataFactoryInterface $statsDataFactory, |
135 | TempUserConfig $tempUserConfig, |
136 | AnonymousEditWarningBuilder $anonymousEditWarningBuilder, |
137 | MediaWikiEditEntityFactory $editEntityFactory, |
138 | EntityNamespaceLookup $entityNamespaceLookup, |
139 | EntityTitleStoreLookup $entityTitleLookup, |
140 | EntityLookup $entityLookup, |
141 | EntityIdParser $entityIdParser, |
142 | SettingsArray $repoSettings, |
143 | SummaryFormatter $summaryFormatter, |
144 | EntityIdFormatterFactory $entityIdFormatterFactory, |
145 | FallbackLabelDescriptionLookupFactory $labelDescriptionLookupFactory, |
146 | ValidatorErrorLocalizer $validatorErrorLocalizer, |
147 | LemmaTermValidator $lemmaTermValidator |
148 | ): self { |
149 | $copyrightView = new SpecialPageCopyrightView( |
150 | new CopyrightMessageBuilder(), |
151 | $repoSettings->getSetting( 'dataRightsUrl' ), |
152 | $repoSettings->getSetting( 'dataRightsText' ) |
153 | ); |
154 | |
155 | return new self( |
156 | $repoSettings->getSetting( 'specialPageTags' ), |
157 | $copyrightView, |
158 | $linkRenderer, |
159 | $statsDataFactory, |
160 | $editEntityFactory, |
161 | $entityNamespaceLookup, |
162 | $entityTitleLookup, |
163 | $entityLookup, |
164 | $entityIdParser, |
165 | $summaryFormatter, |
166 | $entityIdFormatterFactory, |
167 | $labelDescriptionLookupFactory, |
168 | $validatorErrorLocalizer, |
169 | $lemmaTermValidator, |
170 | $anonymousEditWarningBuilder, |
171 | $tempUserConfig |
172 | ); |
173 | } |
174 | |
175 | public function doesWrites(): bool { |
176 | return true; |
177 | } |
178 | |
179 | /** |
180 | * @param string|null $subPage |
181 | */ |
182 | public function execute( $subPage ): void { |
183 | $this->statsDataFactory->increment( 'wikibase.lexeme.special.NewLexeme.views' ); |
184 | |
185 | parent::execute( $subPage ); |
186 | |
187 | $this->checkBlocked(); |
188 | $this->checkBlockedOnNamespace(); |
189 | $this->checkReadOnly(); |
190 | |
191 | $output = $this->getOutput(); |
192 | $this->setHeaders(); |
193 | $searchUrl = SpecialPage::getTitleFor( 'Search' ) |
194 | ->getFullURL( [ |
195 | 'ns' . $this->getConfig()->get( 'LexemeNamespace' ) => '', |
196 | 'search' => $this->getRequest()->getText( self::FIELD_LEMMA ), |
197 | ] ); |
198 | $searchExisting = $this->msg( 'wikibaselexeme-newlexeme-search-existing' ) |
199 | ->params( $searchUrl ) |
200 | ->parse(); |
201 | $output->addHTML( |
202 | '<div id="wbl-snl-intro-text-wrapper">' |
203 | . '<p class="wbl-snl-search-existing-no-js">' . $searchExisting . '</p>' |
204 | . '</div>' |
205 | ); |
206 | $output->enableOOUI(); |
207 | $output->addHTML( $this->anonymousEditWarning() ); |
208 | $output->addHTML( '<div class="wbl-snl-main-content">' ); |
209 | $output->addHTML( '<div id="special-newlexeme-root"></div>' ); |
210 | $output->addModules( [ |
211 | 'wikibase.lexeme.special.NewLexeme', |
212 | 'wikibase.lexeme.special.NewLexeme.legacyBrowserFallback', |
213 | ] ); |
214 | $output->addModuleStyles( [ |
215 | 'wikibase.lexeme.special.NewLexeme.styles', |
216 | 'wikibase.alltargets', // T322687 |
217 | ] ); |
218 | |
219 | $exampleLexemeParams = $this->createExampleParameters(); |
220 | $form = $this->createForm( $exampleLexemeParams ); |
221 | $form->setSubmitText( $this->msg( 'wikibaselexeme-newlexeme-submit' ) ); |
222 | |
223 | // handle submit (submit callback may create form, see below) |
224 | // or show form (possibly with errors); status represents submit result |
225 | $status = $form->show(); |
226 | $output->addModuleStyles( [ |
227 | 'oojs-ui.styles.icons-content', // info icon |
228 | 'oojs-ui.styles.icons-alert', // alert icon |
229 | ] ); |
230 | $output->addHTML( |
231 | $this->processInfoPanelTemplate( $exampleLexemeParams ) |
232 | ); |
233 | $output->addHTML( '</div>' ); // .wbl-snl-main-content |
234 | $output->addHTML( |
235 | '<noscript>' |
236 | . '<style type="text/css">#special-newlexeme-root {display:none;}</style>' |
237 | . '</noscript>' |
238 | ); |
239 | |
240 | if ( $status instanceof Status && $status->isGood() ) { |
241 | // wrap it, in case HTMLForm turned it into a generic Status |
242 | $status = EditEntityStatus::wrap( $status ); |
243 | $this->redirectToEntityPage( $status ); |
244 | return; |
245 | } |
246 | |
247 | $output->addJsConfigVars( 'wblSpecialNewLexemeParams', |
248 | $this->getUrlParamsForConfig() |
249 | ); |
250 | $output->addJsConfigVars( |
251 | 'wblSpecialNewLexemeLexicalCategorySuggestions', |
252 | $this->getLexicalCategorySuggestions() |
253 | ); |
254 | $output->addJsConfigVars( 'wblSpecialNewLexemeTempUserEnabled', |
255 | $this->tempUserConfig->isEnabled() |
256 | ); |
257 | $output->addJSConfigVars( |
258 | 'wblSpecialNewLexemeExampleData', |
259 | [ |
260 | 'languageLabel' => $exampleLexemeParams['language_item_label'], |
261 | 'lexicalCategoryLabel' => $exampleLexemeParams['lexical_category_item_label'], |
262 | 'lemma' => $exampleLexemeParams['lemma_text'], |
263 | 'spellingVariant' => $exampleLexemeParams['lemma_language'], |
264 | ] |
265 | ); |
266 | } |
267 | |
268 | private function getUrlParamsForConfig(): array { |
269 | $params = []; |
270 | $lemma = $this->getRequest()->getText( self::FIELD_LEMMA ); |
271 | if ( $lemma ) { |
272 | $params['lemma'] = $lemma; |
273 | } |
274 | |
275 | $spellVarCode = $this->getRequest()->getText( self::FIELD_LEMMA_LANGUAGE ); |
276 | if ( $spellVarCode ) { |
277 | $params['spellVarCode'] = $spellVarCode; |
278 | } |
279 | |
280 | try { |
281 | $languageId = $this->entityIdParser->parse( |
282 | $this->getRequest()->getText( self::FIELD_LEXEME_LANGUAGE ) |
283 | ); |
284 | } catch ( EntityIdParsingException $e ) { |
285 | $languageId = null; |
286 | } |
287 | try { |
288 | $lexCatId = $this->entityIdParser->parse( |
289 | $this->getRequest()->getText( self::FIELD_LEXICAL_CATEGORY ) |
290 | ); |
291 | } catch ( EntityIdParsingException $e ) { |
292 | $lexCatId = null; |
293 | } |
294 | |
295 | $idsToPrefetch = array_filter( [ $languageId, $lexCatId ] ); |
296 | if ( !$idsToPrefetch ) { |
297 | return $params; |
298 | } |
299 | |
300 | $labelDescriptionLookup = $this->labelDescriptionLookupFactory->newLabelDescriptionLookup( |
301 | $this->getLanguage(), |
302 | $idsToPrefetch, |
303 | [ TermTypes::TYPE_LABEL, TermTypes::TYPE_DESCRIPTION ] |
304 | ); |
305 | |
306 | if ( $languageId ) { |
307 | $params['language'] = $this->getItemIdLabelDesc( $languageId, $labelDescriptionLookup ); |
308 | $params['language']['languageCode'] = $this->extractLanguageCode( $languageId ); |
309 | } |
310 | |
311 | if ( $lexCatId ) { |
312 | $params['lexicalCategory'] = $this->getItemIdLabelDesc( $lexCatId, $labelDescriptionLookup ); |
313 | } |
314 | |
315 | return $params; |
316 | } |
317 | |
318 | private function getItemIdLabelDesc( |
319 | EntityId $itemId, |
320 | FallbackLabelDescriptionLookup $labelDescriptionLookup |
321 | ): array { |
322 | $params = [ 'display' => [] ]; |
323 | $params['id'] = $itemId->getSerialization(); |
324 | $label = $labelDescriptionLookup->getLabel( $itemId ); |
325 | if ( $label !== null ) { |
326 | $params['display']['label'] = self::termToArrayForJs( $label ); |
327 | } |
328 | $description = $labelDescriptionLookup->getDescription( $itemId ); |
329 | if ( $description !== null ) { |
330 | $params['display']['description'] = self::termToArrayForJs( $description ); |
331 | } |
332 | |
333 | return $params; |
334 | } |
335 | |
336 | private function extractLanguageCode( EntityId $languageId ) { |
337 | $lexemeLanguageCodePropertyIdString = $this->getConfig()->get( 'LexemeLanguageCodePropertyId' ); |
338 | if ( !$lexemeLanguageCodePropertyIdString ) { |
339 | return null; |
340 | } |
341 | $languageItem = $this->entityLookup->getEntity( $languageId ); |
342 | if ( !( $languageItem instanceof Item ) ) { |
343 | return null; |
344 | } |
345 | $lexemeLanguageCodePropertyId = $this->entityIdParser->parse( |
346 | $lexemeLanguageCodePropertyIdString |
347 | ); |
348 | if ( !( $lexemeLanguageCodePropertyId instanceof PropertyId ) ) { |
349 | throw new ConfigException( |
350 | 'LexemeLanguageCodePropertyId must be a property ID, but isn’t: ' . $lexemeLanguageCodePropertyIdString |
351 | ); |
352 | } |
353 | $languageCodeStatements = $languageItem->getStatements()->getByPropertyId( |
354 | $lexemeLanguageCodePropertyId |
355 | )->getBestStatements(); |
356 | if ( !$languageCodeStatements->isEmpty() ) { |
357 | $firstBestSnak = $languageCodeStatements->getMainSnaks()[0]; |
358 | if ( $firstBestSnak instanceof PropertyValueSnak ) { |
359 | return $firstBestSnak->getDataValue()->getValue(); |
360 | } |
361 | if ( $firstBestSnak instanceof PropertySomeValueSnak ) { |
362 | return false; |
363 | } |
364 | } |
365 | return null; |
366 | } |
367 | |
368 | private function createExampleParameters(): array { |
369 | $exampleMessage = $this->msg( 'wikibaselexeme-newlexeme-info-panel-example-lexeme-id' ); |
370 | if ( $exampleMessage->exists() ) { |
371 | $lexemeIdString = trim( $exampleMessage->text() ); |
372 | } else { |
373 | $lexemeIdString = 'L1'; |
374 | } |
375 | try { |
376 | return $this->createTemplateParamsFromLexemeId( $lexemeIdString ); |
377 | } catch ( Exception $_ ) { |
378 | return [ |
379 | 'lexeme_id_HTML' => 'L1', |
380 | 'lemma_text' => 'speak', |
381 | 'lemma_language' => 'en', |
382 | 'language_item_id' => 'Q1', |
383 | 'language_item_label' => self::FALLBACK_LANGUAGE_LABEL, |
384 | 'language_link_HTML' => self::FALLBACK_LANGUAGE_LABEL, |
385 | 'lexical_category_item_id' => 'Q2', |
386 | 'lexical_category_item_label' => self::FALLBACK_LEXICAL_CATEGORY_LABEL, |
387 | 'lexical_category_link_HTML' => self::FALLBACK_LEXICAL_CATEGORY_LABEL, |
388 | ]; |
389 | } |
390 | } |
391 | |
392 | private function createTemplateParamsFromLexemeId( string $lexemeIdString ): array { |
393 | try { |
394 | $lexemeId = $this->entityIdParser->parse( $lexemeIdString ); |
395 | $lexeme = $this->entityLookup->getEntity( $lexemeId ); |
396 | } catch ( EntityIdParsingException $e ) { |
397 | $lexeme = null; |
398 | } |
399 | if ( !( $lexeme instanceof Lexeme ) ) { |
400 | throw new ConfigException( |
401 | 'MediaWiki:wikibaselexeme-newlexeme-info-panel-example-lexeme-id must be ' . |
402 | 'the ID of an existing lexeme, but isn’t: ' . $lexemeIdString |
403 | ); |
404 | } |
405 | |
406 | $lemma = $lexeme->getLemmas()->getIterator()->current(); |
407 | $lexemeIdLink = $this->linkRenderer->makeKnownLink( |
408 | $this->entityTitleLookup->getTitleForId( $lexemeId ), |
409 | $lexemeIdString |
410 | ); |
411 | |
412 | $labelDescriptionLookup = $this->labelDescriptionLookupFactory->newLabelDescriptionLookup( |
413 | $this->getLanguage(), |
414 | [ $lexeme->getLanguage(), $lexeme->getLexicalCategory() ], |
415 | [ TermTypes::TYPE_LABEL ] |
416 | ); |
417 | |
418 | $entityIdFormatter = $this->entityIdFormatterFactory->getEntityIdFormatter( $this->getLanguage() ); |
419 | $languageLabel = $labelDescriptionLookup->getLabel( $lexeme->getLanguage() ); |
420 | $lexicalCategoryLabel = $labelDescriptionLookup->getLabel( $lexeme->getLexicalCategory() ); |
421 | |
422 | return [ |
423 | 'lexeme_id_HTML' => $lexemeIdLink, |
424 | 'lemma_text' => $lemma->getText(), |
425 | 'lemma_language' => $lemma->getLanguageCode(), |
426 | 'language_item_id' => $lexeme->getLanguage()->getSerialization(), |
427 | 'language_item_label' => $languageLabel ? |
428 | $languageLabel->getText() : |
429 | self::FALLBACK_LANGUAGE_LABEL, |
430 | 'language_link_HTML' => $entityIdFormatter->formatEntityId( $lexeme->getLanguage() ), |
431 | 'lexical_category_item_id' => $lexeme->getLexicalCategory()->getSerialization(), |
432 | 'lexical_category_item_label' => $lexicalCategoryLabel ? |
433 | $lexicalCategoryLabel->getText() : |
434 | self::FALLBACK_LEXICAL_CATEGORY_LABEL, |